Dans l’article précédent, je vous ai expliqué comment installer la bonne version de certbot pour générer des certificats wildcard letsencrypt et je vous ai montré comment en générer un avec une édition manuelle de la zone DNS.
Dans ce second article de cette série sur la génération de certificats wildcard letsencrypt, je vais vous montrer comment générer automatiquement un certificat wildcard.
Nous allons commencer par un domaine dont le DNS est géré sur un fournisseur DNS pour lequel il exist un plugin pour certbot. Nous utiliserons AWS route53 dans cet exemple
Ensuite, nous verrons comment utiliser des scripts maison pour faire l’ajout de l’entrée DNS nécessaire au challenge ACME DNS-01 (le protocole de validation pour l’émission du certificat wildcard). Nous utiliserons cette technique pour générer des certificats lorsque la zone DNS est hébergée sur un bind local ou lorsqu’elle est hébergée sur les DNS de gandi (LiveDNS) ou d'OVH.
Génération de certificat wildcard avec DNS route53
Pour pouvoir créer les entrées DNS nécessaires à la validation du domaine, il vous faudra une clé d’accès et une clé secrète pour l’API AWS. Vous devez donc commencer par créer un utilisateur dans la console IAM de la façon suivante :
- Choisissez “Ajouter un utilisateur”
-
Appelez-le “letsencrypt_validation” par exemple et choisissez un accès par programmation (pour obtenir une clé d’API) et cliquez sur “Suivant”
-
Choisissez d’attacher directement les stratégies existantes et cliquez sur “Créer une stratégie” pour créer les droits de votre nouvel utilisateur
-
Créez une nouvelle stratégie pour le service Route53 qui autorise les actions “GetChange”, “ListHostedZones” et “ChangeRessourceRecordSets” sur tous les objets (vous pouvez sinon restreindre l’action “ChangeRessourceRecordSets” sur les seuls domaines pour lesquels vous souhaitez pouvoir effectuer une validation DNS-01)
-
Nommez votre stratégie (par exemple letsencrypt_validation) et validez
-
Revenez à votre utilisateur en cours de création, cliquez sur “Actualiser” pour recharger la liste des stratégies puis recherchez celle que vous venez de créer et cochez la case en début de ligne pour l’associer à votre utilisateur, puis cliquez sur “Suivant”
-
Vérifiez le résumé et cliquez sur “Créer un utilisateur” pour procéder à la création
-
Dans le résumé de création de l’utilisateur, notez l’ID de clé d’accès ainsi que la clé d’accès secrète qui vous serviront à vous authentifier auprès de l’API route53
Le plugin route53 de certbot utilise ces identifiants. Nous allons donc installer le paquet awscli
et configurer les identifiants :
$ apt-get install awscli
$ aws configure
AWS Access Key ID [None]: AKIAXXXXXXXXXXXXXXXX
AWS Secret Access Key [None]: 74Bo!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Default region name [None]: eu-central-1
Default output format [None]:
Nous allons ensuite installer le plugin route53 de certbot :
$ /opt/eff.org/certbot/venv/bin/pip install certbot-route53
Collecting certbot-route53
Downloading certbot-route53-0.2.0.tar.gz
[...]
Successfully built certbot-route53
Installing collected packages: jmespath, python-dateutil, docutils, botocore, futures, s3transfer, boto3, certbot-dns-route53, certbot-route53
Successfully installed boto3-1.6.11 botocore-1.9.11 certbot-dns-route53-0.22.0 certbot-route53-0.2.0 docutils-0.14 futures-3.2.0 jmespath-0.9.3 python-dateutil-2.6.1 s3transfer-0.1.13
Et nous avons désormais tout ce qu’il nous faut pour générer un certificat wildcard letsencrypt avec un domaine géré sur route53. Nous utiliserons les options suivantes de certbot :
--server https://acme-v02.api.letsencrypt.org/directory
On utilise l’API ACME v2--dns-route53
L’entrée DNS pour le challenge sera créée via l’api route53-d '*.domain.tld'
le sujet du certificat qu’on souhaite émettre
$ cd /opt/eff.org/certbot/venv/bin
$ ./certbot certonly \
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--dns-route53 \
-d '*.domain.tld'
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Found credentials in shared credentials file: ~/.aws/credentials
Plugins selected: Authenticator dns-route53, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for domain.tld
Starting new HTTPS connection (1): route53.amazonaws.com
Waiting 10 seconds for DNS changes to propagate
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/domain.tld/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/domain.tld/privkey.pem
Your cert will expire on 2018-06-15. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Et voilà ! nous avons généré automatiquement notre certificat wildcard letsencrypt pour un domaine géré sur route53. Et comme la validation s’est faite automatiquement, sans intervention manuelle, la renouvèlement se passera de la même façon.
Génération de certificat wildcard avec scripts maison d’édition de zone
Fonctionnement
Lors d’une génération de certificat avec validation manuelle, certbot
dispose des options --manual-auth-hook
et --manual-cleanup-hook
qui permettent de définir des scripts qui doivent être appelés pour créer l’entrée dns avant la validation puis pour la supprimer après. Voir à ce sujet la documentation officielle.
Ces scripts sont appelés avec les variables d’environnements suivantes définies (pour une validation DNS-01) :
CERTBOT_DOMAIN
: le domaine à validerCERTBOT_VALIDATION
: le contenu de l’entrée TXT à créer
Le script de nettoyage post-validation reçoit également la variable d’environnement CERBOT_AUTH_OUTPUT
qui contient la sortie standard du script de validation. Ceci peut servir par exemple à passer entre les 2 scripts l’ID de l’enregistrement créé.
Je vous ai mis dans github tous les scripts utilisés ci-dessous. Ces scripts sont des exemples pour vous aider à développer les vôtres. Commencez par cloner ces scripts dans /opt/le-scripts
:
$ git clone https://github.com/sblaisot/certbot-dns-01-authenticators.git /opt/le-scripts
4 ensembles de scripts sont disponibles, le premier pour tester le fonctionnement de certbot avec des scripts de validation personnels, le second si vous avez votre serveur DNS bind sur la même machine que celle avec laquelle pour générez les certificats et les deux derniers pour générer des certificats wildcard letsencrypt lorsque vos zones DNS sont gérées sur le service LiveDNS de Gandi ou chez OVH.
Chaque ensemble est composé de 2 scripts : un script auth
qui permet de créer l’entrée DNS pour la validation et un script cleanup
qui permet de la retirer une fois la validation effectuée.
Un script pour tester
Les scripts du répertoire test
se contentent d’afficher le contenu des variables d’environnements passées par certbot, pour en étudier le fonctionnement. De ce fait, ils ne créent ni ne suppriment aucune entrée DNS et la génération de certificat échoue forcément.
Néanmoins, ils nous permettent de voir comment cela fonctionne. Appelons certbot
en lui demandant d’utiliser ces scripts :
$ cd /opt/eff.org/certbot/venv/bin
$ ./certbot certonly \
--server https://acme-staging-v02.api.letsencrypt.org/directory \
--manual-public-ip-logging-ok \
--manual \
--manual-auth-hook /opt/le-scripts/test/auth.sh \
--manual-cleanup-hook /opt/le-scripts/test/cleanup.sh \
-d '*.domain.tld'
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for domain.tld
Output from auth.sh:
------ AUTH ------
CERTBOT_VALIDATION=39sbL18pMHYSusn0zZoenN3kUtJyq7DU-XnpzkFQdBA
CERTBOT_DOMAIN=domain.tld
------ AUTH ------
Waiting for verification...
Cleaning up challenges
Output from cleanup.sh:
------ CLEANUP ------
CERTBOT_VALIDATION=39sbL18pMHYSusn0zZoenN3kUtJyq7DU-XnpzkFQdBA
CERTBOT_DOMAIN=domain.tld
CERTBOT_AUTH_OUTPUT=------ AUTH ------
CERTBOT_VALIDATION=39sbL18pMHYSusn0zZoenN3kUtJyq7DU-XnpzkFQdBA
CERTBOT_DOMAIN=domain.tld
------ AUTH ------
------ CLEANUP ------
Failed authorization procedure. domain.tld (dns-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: No TXT record found at _acme-challenge.domain.tld
IMPORTANT NOTES:
- The following errors were reported by the server:
Domain: domain.tld
Type: unauthorized
Detail: No TXT record found at _acme-challenge.domain.tld
To fix these errors, please make sure that your domain name was
entered correctly and the DNS A/AAAA record(s) for that domain
contain(s) the right IP address.
Nous voyons ici que les scripts sont appelés avant la validation pour créer l’entrée DNS et après la validation pour la supprimer. Ces scripts reçoivent bien les variables d’environnement de certbot
.
Génération de certificat wildcard avec DNS bind local
Le répertoire local-bind
contient des scripts qui permettent d’ajouter l’entrée de validation dans des fichiers de zone bind accessible en local sur la machine qui émet le certificat.
Ces scripts freezent la zone dns (pour éviter une rotation de clé dnssec lors de l’ajout de l’entrée), mettent à jour le numéro de série de la zone et ajoutent l’entrée (ou la suppriment pour le script de cleanup)
Pour les utiliser, copiez le fichier config.sh.example
en config.sh
et adaptez le pour y indiquer l’emplacement de vos fichiers de zone, le format de leur nom (qui doit contenir le nom de domaine) ainsi que la chaine à rechercher pour trouver le serial de la zone.
Vous pourrez ensuite générer votre certificat wildcard de la façon suivante :
$ cd /opt/eff.org/certbot/venv/bin
$ ./certbot certonly \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual-public-ip-logging-ok \
--manual \
--manual-auth-hook /opt/le-scripts/local-bind/auth.sh \
--manual-cleanup-hook /opt/le-scripts/local-bind/cleanup.sh \
-d '*.domain.tld'
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for domain.tld
Output from auth.sh:
Freeze zone
Update serial
Add challenge to zone file
Release zone
A zone reload and thaw was started.
Check the logs to see the result.
Wait 5 seconds for repplication to masters
Done
Waiting for verification...
Cleaning up challenges
Output from cleanup.sh:
Freeze zone
Update serial
Remove challenge from zone file
Release zone
A zone reload and thaw was started.
Check the logs to see the result.
Done
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/domain.tld/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/domain.tld/privkey.pem
Your cert will expire on 2018-06-16. To obtain a new or tweaked
version of this certificate in the future, simply run
letsencrypt-auto again. To non-interactively renew *all* of your
certificates, run "letsencrypt-auto renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Il serait également possible de configurer bind pour accepter les mises à jour dynamiques (rfc2136) et utiliser le plugin dns-rfc2136
de certbot. Je vous le laisse en exercice ;)
Génération de certificat wildcard avec DNS Gandi (LiveDNS)
Maintenant qu’on a bien joué avec nos scripts de test, voici un exemple plus près de la vie réelle pour la génération d’un certificat wildcard lorsque la zone DNS est hébergée chez Gandi.
Il est indispensable que votre zone DNS soit hébergée sur la solution LiveDNS de gandi (v5) qui permet une mise à jour des enregistrement DNS instantanée contrairement à l’ancienne solution (v4). Dans l’ancienne version, il fallait plusieurs minutes pour que vos enregistrements DNS soient créés et ceci n’est pas compatible avec la validation de domaine.
Ensuite, il vous suffit dans le répertoire /opt/le-scripts/gandi-livedns
de copier le fichier config.py.example
en config.py
et d’ajuster les paramètres :
livedns_api = "https://dns.api.gandi.net/api/v5/"
c’est le endpoint de l’API LiveDNS de Gandi. Il n’est habituellement pas nécessaire de modifier ce paramètrelivedns_apikey = "YOUR-KEY-HERE"
Votre clé d’API LiveDNS que vous pourrez générer dans vos paramètres de compte à la rubrique “Modification de mot de passe et configuration des restrictions d’accès“livedns_sharing_id = None
Si vos domaines ne sont pas rattachés directement à votre compte mais gérés dans une organisation, il faudra indiquer ici votresharing_id
qui permet de gérer l’organisation à partir de votre compte. Vous le retrouverez dans l’URL du manager lorsque vous listez votre domaine sous la forme d'un GUID.
Une fois la configuration effectuée, il ne vous reste plus qu’à générer votre certificat :
$ cd /opt/eff.org/certbot/venv/bin
$ ./certbot certonly \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual-public-ip-logging-ok \
--manual \
--manual-auth-hook /opt/le-scripts/gandi-livedns/auth.py \
--manual-cleanup-hook /opt/le-scripts/gandi-livedns/cleanup.py \
-d '*.domain.tld'
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for domain.tld
Output from auth.py:
all good, entry created
Waiting for verification...
Cleaning up challenges
Output from cleanup.py:
all good, entry deleted
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/domain.tld/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/domain.tld/privkey.pem
Your cert will expire on 2018-06-15. To obtain a new or tweaked
version of this certificate in the future, simply run
letsencrypt-auto again. To non-interactively renew *all* of your
certificates, run "letsencrypt-auto renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Génération de certificat wildcard avec DNS OVH
Et si vos domaines sont hébergés chez OVH, c'est la même chose.
On installe d'abord les prérequis :
$ sudo apt-get install python3-dnspython
$ sudo pip3 install ovh
Vous devez ensuite copier le fichier /opt/le-scripts/ovh/ovh.conf.example
en /opt/le-scripts/ovh/ovh.conf
et l'ajuster avec vos clés d'api.
Et vous pouvez ensuite génèrer le certificat :
$ cd /opt/eff.org/certbot/venv/bin/
$ ./certbot certonly \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual-public-ip-logging-ok \
--manual \
--manual-auth-hook /opt/le-scripts/ovh/auth.py \
--manual-cleanup-hook /opt/le-scripts/ovh/cleanup.py \
-d '*.domain.tld'
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for domain.tld
Output from auth.py:
All good, DNS record created
Waiting for record to be available on DNS servers
DNS record available on DNS server
Waiting for verification...
Cleaning up challenges
Output from cleanup.py:
All good, DNS record deleted
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/domain.tld/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/domain.tld/privkey.pem
Your cert will expire on 2018-06-17. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Points complémentaires
Emplacement des scripts et renouvèlement
Si vous devez déplacer les scripts sur votre système, le renouvèlement de certificat risque de ne pas les trouver, et donc d’échouer. Il vous faut alors mettre à jour le fichier de configuration du renouvèlement qui se trouve dans /etc/letsencrypt/renewal/<domain>.conf
Délai de création de l’entrée DNS
Il est indispensable pour la validation automatique (et donc pour le renouvèlement) que votre système DNS permette de créer immédiatement une entrée DNS. S’il vous faut plusieurs minutes/heures/jours pour que l’entrée DNS soit créée, vous ne pourrez pas générer de certificat wildcard avec cette méthode. Bien que le protocole ACME semble semble permettre la validation asynchrone, je ne sais pas quelle est la durée de vie maximale du jeton d’authentification et le client certbot ne le permet pas, il vous faudra donc trouver ou coder un autre client ACME.
Mais Hey, on est en 2018, il y a plein de super services DNS qui permettent de mettre en ligne immédiatement une entrée, avec un pilotage par api. Il est peut-être temps de changer de fournisseur DNS dans ce cas.
Et la sécurité dans tout ça ?
Dans les exemples donnés, le serveur qui génère le certificat letsencrypt a un contrôle total sur la zone DNS. Il n’est pas souhaitable, en réalité, que le serveur web qui a besoin du certificat ait la possibilité de modifier tout le contenu de la zone DNS.
Dans ce cas, vous pouvez imaginer générer le certificat à partir d’une machine d’administration puis le pousser sur le serveur web qui en a besoin, ou développer une api interne accessible par le serveur web qui permette uniquement de gérer l’entrée _acme-challenge
et qui fera le relai vers le fournisseur DNS.
Conclusion
Vous avez maintenant tous les éléments en main pour générer des certificats letsencrypt. Si vous vous posez encore des questions, n’hésitez pas à les laisser en commentaire, j’essaierai d’y répondre.
Comments
comments powered by Disqus