systemli.letsencrypt
Rôle Ansible pour obtenir des certificats SSL Let's Encrypt
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
etwebroot
sont pris en charge
- Pour le défi HTTP, les plugins d'authentification
- 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']
- pour http_auth 'webroot' :
- pour le défi 'http' :
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 verssub.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
etletsencrypt_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/)
ansible-galaxy install systemli.letsencrypt