systemli.letsencrypt

Rôle Ansible pour obtenir des certificats SSL Let's Encrypt

Intégration Ansible Galaxy

Ce rôle est conçu pour demander des certificats SSL à Let's Encrypt, en utilisant le défi HTTP ou le défi DNS pour leur API ACME.

Caractéristiques :

  • Installe et configure certbot et le script d'aide pour le défi DNS
  • Prend en charge le défi HTTP et le défi DNS
    • Pour le défi HTTP, les plugins d'authentification apache, nginx, standalone et webroot sont pris en charge
  • Le défi DNS utilise une zone dédiée uniquement pour les jetons de défi AMCE, réduisant les risques de sécurité liés aux mises à jour dynamiques. Le concept est expliqué ici
  • Redémarrage des services lors du renouvellement du certificat à l'aide de post-hooks ou de commandes post-hook personnalisées
  • Contrôle des permissions pour les certificats à l'aide d'un groupe système dédié

Distributions prises en charge :

  • Debian 11 (Bullseye)
  • Debian 12 (Bookworm)

Testé sur :

  • Debian 11 (Bullseye)
  • Debian 12 (Bookworm)
  • CentOS7
  • Ubuntu 2204 (Jammy Jellyfish)

Il fait ce qui suit :

  • Lorsque letsencrypt_setup est vrai (par défaut), ce rôle va :

    • Installer certbot
    • Enregistrer un compte auprès de Let's Encrypt
    • Installer les fichiers/clés nécessaires pour le défi DNS
    • Créer le groupe système 'letsencrypt'
  • Lorsqu'il est invoqué avec la variable remplie 'letsencrypt_cert' :

    • Demande un certificat SSL via l'API ACME de Let's Encrypt, soit en utilisant le défi HTTP soit en utilisant le défi DNS
    • Définit facultativement le post-hook pour les renouvellements de certificats (pour redémarrer les services nécessaires ensuite)
    • Ajoute éventuellement des utilisateurs système au groupe système 'letsencrypt' pour leur donner un accès en lecture aux certificats SSL et à leurs clés privées

Comment ça fonctionne (exemples)

  • Installation de certbot ansible-playbook site.yml -l localhost -t letsencrypt
  • Création d'un certificat via le défi HTTP et avec l'authentificateur webroot (redémarrage du service 'apache2' lors du renouvellement) : ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub.example.org","domains":["sub.example.org"],"challenge":"http","http_auth":"webroot","webroot_path":"/var/www/sub.example.org","services":["apache2"]}}'
  • Création d'un certificat via le défi DNS (accordant un accès en lecture aux certificats à l'utilisateur 'Debian-exim', redémarrage des services 'exim4' et 'dovecot' lors du renouvellement) : ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub2","domains":["sub2.example.org","sub2.another.example.org"],"challenge":"dns","services":["dovecot","exim4"],"users":["Debian-exim"]}}'
  • Création d'un certificat via le défi HTTP et avec l'authentificateur standalone (réutilisation de la même clé privée lors du renouvellement et exécution d'un script post-hook personnalisé lors du renouvellement) : ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub3","domains":["sub3.example.org"],"challenge":"http","http_auth":"standalone","reuse_key":True,"post_hook":"/usr/local/bin/cert-post-hook.sh"}}'

Structure attendue de la variable letsencrypt_cert

La variable letsencrypt_cert doit être un dictionnaire :

letsencrypt_opts_extra: "--register-unsafely-without-email"
letsencrypt_cert:
  name: sub.example.org
  domains:
    - sub.example.org
  challenge: http
  http_auth: webroot
  webroot_path: /var/www/sub.example.org
  services:
    - apache2

ou :

letsencrypt_cert:
  name: sub2
  domains:
    - sub2.example.org
    - sub2.another.example.org
  challenge: dns
  services:
    - dovecot
    - exim4
  users:
    - Debian-exim

ou :

letsencrypt_cert:
  name: sub3
  domains:
    - sub3.example.org
  challenge: http
  http_auth: standalone
  reuse_key: True
  post_hook: "/usr/local/bin/cert-post-hook.sh"
letsencrypt_cert:
  name: sub3
  domains:
    - sub3.example.org
  challenge: http
  http_auth: standalone
  reuse_key: True
  deploy_hook: "/usr/local/bin/cert-post-hook.sh"

Le dictionnaire prend en charge les clés suivantes :

  • name : nom du certificat [optionnel]
  • domains : liste des domaines pour le certificat [requis]
  • challenge : 'http' ou 'dns' [requis]
    • pour le défi 'http' : http_auth : 'webroot', 'apache' ou 'nginx' [optionnel, par défaut 'webroot']
      • pour http_auth 'webroot' : webroot_path [optionnel, par défaut '/var/www']
  • services : liste des services à redémarrer dans le post-hook [optionnel]
  • reuse_key : réutiliser la même clé privée lors du renouvellement du certificat. 'True' ou 'False' (par défaut 'False')
  • post_hook : post-hook personnalisé à exécuter après la tentative d'obtention/renouvellement d'un certificat [optionnel]
  • deploy_hook : déploiement-hook personnalisé à exécuter après une tentative réussie d'obtention/renouvellement d'un certificat [optionnel]
  • renew_hook : renouvellement-hook personnalisé à exécuter une fois pour chaque certificat renouvelé après le renouvellement du certificat [optionnel]
  • users : liste des utilisateurs à ajouter au groupe système 'letsencrypt' [optionnel]

Généralités

Le rôle se charge d'installer certbot et de demander des certificats SSL en utilisant soit le défi HTTP soit le défi DNS. Il n'installe ni ne configure l'infrastructure requise (c'est-à-dire le serveur web Apache ou un serveur DNS).

Le rôle est testé uniquement avec Ansible 2.2. Aucun garantie qu'il fonctionne avec des versions antérieures d'Ansible.

Le défi HTTP

Exigences :

  • Le(s) nom(s) de domaine du certificat demandé doivent pointer vers le système
  • Pour http_auth 'apache', Apache2 doit être installé (et configuré) sur le système
  • Pour http_auth 'nginx', NGINX doit être installé (et configuré) sur le système

Le défi DNS

Exigences :

  • Un serveur DNS avec une zone dédiée, utilisée uniquement pour le défi DNS ACME. Cette zone doit autoriser les mises à jour DNS dynamiques (NSUPDATE) pour les enregistrements TXT (voir ci-dessous).
  • Les enregistrements CNAME pour _acme-challenge.sub.example.org pour tous les noms de domaine du certificat demandé doivent pointer vers sub.example.org._le.example.org (dans la zone dédiée pour le défi DNS ACME).
  • Le contenu de la clé de mise à jour DNS et des clés de mise à jour DNS privées doivent être disponibles dans les variables Ansible letsencrypt_ddns_key et letsencrypt_ddns_privkey (de préférence à l'intérieur d'un coffre-fort).

Ce rôle installe un script d'aide pour le défi DNS à /usr/local/bin/certbot-dns-hook.sh. Ce script ajoutera le jeton de validation à l'enregistrement TXT à sub.example.org._le.example.org pendant le défi DNS et l'enlèvera ensuite.

Prise en charge des certificats wildcard avec le défi DNS

Obtenir des certificats wildcard devrait fonctionner par défaut via le défi DNS.

Configuration de bind9 pour le défi DNS

(Une autre option serait d'utiliser le serveur acme-dns pour cela)

Générez une clé pour les mises à jour dynamiques :

cd /etc/bind/keys
dnssec-keygen -a HMAC-SHA512 -b 512 -n USER _le.example.org_ddns_update
chown -R bind:bind /etc/bind/keys

Ajoutez la clé à votre configuration bind (par exemple dans /etc/bind/named.conf.options) :

key "_le.example.org_ddns_update" {
    algorithm hmac-sha512;
    secret "...";
};

Créez la zone pour les mises à jour dynamiques :

$ORIGIN .
$TTL 86400	; 1 jour
_le.example.org		IN SOA	ns1.example.org. postmaster.example.org. (
                2017061501 ; numéro de série
                86400      ; rafraîchir (1 jour)
                3600       ; réessayer (1 heure)
                2419200    ; expirer (4 semaines)
                86400      ; minimum (1 jour)
                )
            NS	ns1.example.org.
            NS	ns2.example.org.
            TXT	"v=spf1 -all"

et configurez-le dans votre configuration bind (par exemple dans /etc/bind/named.conf.local) :

zone "_le.example.org" {
    type master;
    file "/etc/bind/zones/db._le.example.org";
    update-policy { grant _le.example.org_ddns_update wildcard *._le.example.org. TXT; };
};

Format de /etc/letsencrypt/keys/ddns_update.key (de bind)

key "<key>" {
    algorithm HMAC-SHA512;
    secret "<key>";
};

Format de /etc/letsencrypt/keys/ddns_update.private

Private-key-format: v1.3
Algorithm: 165 (HMAC_SHA512)
Key: <key>
Bits: AAA=
Created: 20181017144534
Publish: 20181017144534
Activate: 20181017144534

Valeurs par défaut des variables Ansible

# Effectuer l'étape de configuration ; définir sur faux pour désactiver
letsencrypt_setup: True

# Fournir les données de compte existantes à copier
letsencrypt_account: ""
# letsencrypt_account:
#   hash: 1234567890abcdef1234567890abcdef
#   id: 123456789
#   creation_host: localhost
#   creation_dt: 2020-12-13T13:12:00Z
#   private_key:
#     n: 1234
#     e: 5678
#     d: 90ab
#     p: cdef
#     q: 1234
#     dp: 5678
#     dq: 90ab
#     qi: cdef
#     kty: RSA

# Définir l'adresse e-mail associée au compte Let's Encrypt
letsencrypt_account_email: ""

# Authentificateur par défaut pour le défi HTTP ('webroot' ou 'apache')
letsencrypt_http_auth: webroot

# Chemin par défaut du webroot pour l'authentificateur 'webroot'
letsencrypt_webroot_path: /var/www

# Installer le script d'aide au défi DNS et la clé de mise à jour DNS
letsencrypt_dns_challenge: yes

# Paramètres pour les mises à jour de zone DNS dynamiques
# letsencrypt_ddns_server: ""
# letsencrypt_ddns_zone: ""
# letsencrypt_ddns_key: ""
# letsencrypt_ddns_privkey: ""

# Créer le groupe système 'letsencrypt' pour accéder aux certificats
letsencrypt_group: yes

# Réutiliser la clé privée lors du renouvellement du certificat ?
letsencrypt_reuse_key: False

# Autoriser un sous-ensemble de noms ?
letsencrypt_subset_names: True

# Définir des options de ligne de commande supplémentaires globales pour certbot
letsencrypt_opts_extra: ""

# Définir le chemin du répertoire letsencrypt (sans "/" à la fin !!)
letsencrypt_directory: /etc/letsencrypt

Tests

Pour des fins de test, la variable letsencrypt_test peut être définie. Si elle est définie sur Vrai, le rôle utilisera les serveurs de test de Let's Encrypt pour la création de comptes et l'obtention du certificat.

Pour développer et tester le rôle, nous utilisons Molecule et Vagrant/Github Actions. Dans l'environnement local, vous pouvez facilement tester le rôle avec

molecule test

Licence

Ce rôle Ansible est sous licence GNU GPLv3.

Auteur

Droits d'auteur 2017-2019 systemli.org (https://www.systemli.org/)

À propos du projet

Role to obtain Let's Encrypt SSL certificates

Installer
ansible-galaxy install systemli.letsencrypt
Licence
gpl-3.0
Téléchargements
25.7k
Propriétaire
Your friendly tech collective