diff --git a/HowtoLetsEncrypt.md b/HowtoLetsEncrypt.md index f643fd82..531e2807 100644 --- a/HowtoLetsEncrypt.md +++ b/HowtoLetsEncrypt.md @@ -5,7 +5,7 @@ title: Howto Let's Encrypt * Documentation : * Documentation Certbot : -* Rôle Ansible : +* Rôle Ansible : [Let's Encrypt](https://letsencrypt.org/) est une autorité de certification fournissant des certificats [SSL](HowtoSSL) valables 90 jours gratuitement et automatiquement. L'obtention d'un certificat signé s'effectue via le protocole [ACME (Automated Certificate Management Environment)](https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment), @@ -15,54 +15,32 @@ Le certificat intermédiaire de Let's Encrypt est également signé par l'autori ## Installation -Un client ACME est nécessaire pour communiquer avec les serveurs de Let's Encrypt et obtenir un certificat. - -Nous utilisons le client officiel [Certbot](https://certbot.eff.org/) disponible via les [backports](HowtoDebian/Backports). - -On ajoute les lignes suivantes à `/etc/apt/preferences.d/backports` : - -~~~ -Package: certbot python-certbot python-acme python-cryptography python-openssl python-setuptools python-ndg-httpsclient python-pyasn1 python-pkg-resources -Pin: release a=jessie-backports -Pin-Priority: 999 -~~~ - -puis on installe certbot et ses dépendances : +On installe certbot et ses dépendances : ~~~ # apt install certbot $ certbot --version -certbot 0.9.3 +certbot 0.31.0 ~~~ -### Création d'un utilisateur dédié - -On évite de faire tourner certbot avec l'utilisateur _root_ (notamment pour ne pas lui donner accès aux clés privées). -Nous allons créer un utilisateur dédié _acme_ : - -~~~ -# adduser --home /var/lib/letsencrypt --quiet --system --no-create-home --group acme -# install -m 755 -o acme -g acme -d /etc/letsencrypt /var/lib/letsencrypt -# install -m 750 -o acme -g acme -d /var/log/letsencrypt -~~~ - -et désactiver la tâche cron `/etc/cron.d/certbot` : - -~~~ -# mv /etc/cron.d/certbot /etc/cron.d/certbot.disabled -~~~ +### ### Configuration du Serveur Web -Pour vérifier que la demande est légitime, Let's Encrypt doit accéder à un fichier temporaire via HTTP sur le port TCP/80 de l'adresse IP correspondant au _Common Name_ du certificat à signer, -du type *http://www.example.com/.well-known/acme-challenge/hNgN_ygEFf-XiHJd6VErwNbfRcpP2CbJmIN3qpJXZOQ* +Pour vérifier que la demande est légitime, Let's Encrypt doit accéder à un fichier temporaire via HTTP sur le port TCP/80 de l'adresse IP correspondant au _Common Name_ du certificat à signer, du type *http://www.example.com/.well-known/acme-challenge/hNgN_ygEFf-XiHJd6VErwNbfRcpP2CbJmIN3qpJXZOQ* #### Apache Configuration : ~~~{.apache} + + SetEnvIf Request_URI "/.well-known/acme-challenge/*" no-jk + + + ProxyPass /.well-known/acme-challenge/ ! + Alias /.well-known/acme-challenge /var/lib/letsencrypt/.well-known/acme-challenge Options -Indexes @@ -73,8 +51,7 @@ Alias /.well-known/acme-challenge /var/lib/letsencrypt/.well-known/acme-challeng #### Nginx -Préférez importer le snippet /etc/nginx/snippets/letsencrypt.conf, -mais si une configuration manuelle est nécessaire: +Préférez importer le snippet `/etc/nginx/snippets/letsencrypt.conf`, mais si une configuration manuelle est nécessaire: Configuration Jessie : @@ -99,24 +76,126 @@ location ~ /.well-known/acme-challenge { ## Génération du certificat -Générer une clé privée (www.example.com.key) et sa demande de certificat associé (www.example.com.csr) (voir [HowtoSSL]()) : - ~~~ -$ certbot certonly -d example.com,www.example.com --cert-name example.com --webroot --webroot-path /var/lib/letsencrypt/ +$ certbot certonly --webroot --webroot-path /var/lib/letsencrypt/ -d example.com,www.example.com --cert-name example.com ~~~ ## Renouvellement du certificat -Les certificats Let's Encrypt sont valables 90 jours. Un timer systemd roule automatiquement à chaque jour pour revalider le certificat. Il est possible d'utiliser --deploy-hook pour faire des actions après un renouvellement. Utiliser systemd edit certbot pour modifier l'invocation par défaut. Par example, pour NGINX, nous modifions +Les certificats Let's Encrypt sont valables 90 jours. Un timer systemd roule automatiquement à chaque jour pour revalider le certificat. -~~~ -ExecStart=/usr/bin/certbot -q renew +Pour effectuer des actions post-renouvellement (recharger le service web, par exemple), on repose sur les hooks. Ils sont automatiquement exécutés s'ils sont détectés et exécutables. + +Pour Apache (`/etc/letsencrypt/renewal-hooks/deploy/apache.sh`): + +~~~{.bash} +#!/bin/sh + +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} +daemon_found_and_running() { + test -n "$(pidof apache2)" && test -n "${apache2ctl_bin}" +} +config_check() { + ${apache2ctl_bin} configtest > /dev/null 2>&1 +} +letsencrypt_used() { + grep -q -r -E "letsencrypt" /etc/apache2/ +} +main() { + if daemon_found_and_running; then + if letsencrypt_used; then + if config_check; then + debug "Apache detected... reloading" + systemctl reload apache2 + else + error "Apache config is broken, you must fix it !" + fi + else + debug "Apache doesn't use Let's Encrypt certificate. Skip." + fi + else + debug "Apache is not running or missing. Skip." + fi +} + +readonly PROGNAME=$(basename "$0") +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} + +readonly apache2ctl_bin=$(command -v apache2ctl) + +main ~~~ -Avec: +Pour Nginx (`/etc/letsencrypt/renewal-hooks/deploy/nginx.sh`) : + +~~~{.bash} +#!/bin/sh + +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} +daemon_found_and_running() { + test -n "$(pidof nginx)" && test -n "${nginx_bin}" +} +config_check() { + ${nginx_bin} -t > /dev/null 2>&1 +} +letsencrypt_used() { + grep -q --dereference-recursive -E "letsencrypt" /etc/nginx/sites-enabled +} +main() { + if daemon_found_and_running; then + if letsencrypt_used; then + if config_check; then + debug "Nginx detected... reloading" + systemctl reload nginx + else + error "Nginx config is broken, you must fix it !" + fi + else + debug "Nginx doesn't use Let's Encrypt certificate. Skip." + fi + else + debug "Nginx is not running or missing. Skip." + fi +} + +readonly PROGNAME=$(basename "$0") +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} + +readonly nginx_bin=$(command -v nginx) + +main +~~~ + +D'autres hooks sont disponibles dans le [dépôt Ansible](https://gitea.evolix.org/evolix/ansible-roles/src/branch/stable/certbot/files/hooks). + +Pour exécuter un hook manuellement, par exemple après la création du certificat : ~~~ -ExecStart=/usr/bin/certbot -q renew --deploy-hook systemctl reload nginx +# VERBOSE=1 RENEWED_LINEAGE=/etc/letsencrypt/live/ /etc/letsencrypt/renewal-hooks/deploy/.sh +~~~ + +## Lister les certificats + +~~~ +# certbot certificates ~~~ ## Suppression d'un certificat @@ -125,9 +204,10 @@ ExecStart=/usr/bin/certbot -q renew --deploy-hook systemctl reload nginx # certbot delete --cert-name www.example.com ~~~ + ## Automatisation -Pour automatiser l'installation de _Certbot_ et la génération/renouvellement de certificats, nous utilisons des scripts : [Evoacme](https://forge.evolix.org/projects/ansible-roles/repository/revisions/stable/show/evoacme). +Pour automatiser l'installation de _Certbot_ et la génération/renouvellement de certificats, nous utilisons des scripts : [Evoacme](https://forge.evolix.org/projects/ansible-roles/repository/revisions/stable/show/certbot). ## FAQ @@ -142,7 +222,7 @@ Let's Encrypt vérifie la légitimité de la demande en faisant une requête DNS ### Challenge DNS -Si notre serveur web n'est pas accessible de l'extérieur, on peut utiliser un challenge par DNS plutôt que via une page http. +Si notre serveur web n'est pas accessible de l'extérieur, on peut utiliser un challenge par DNS plutôt que via une page HTTP. ~~~ $ certbot -d domain.example.com --manual --preferred-challenges dns certonly @@ -161,4 +241,4 @@ L'API de Let's Encrypt dispose un « rate limiting » afin d'éviter les abus. - La limite de renouvellement d'un certificat est de 5 par semaine. Si votre procédure de renouvellement automatique échoue, au bout de 5 jours vous allez être banni pendant 1 semaine. - La limite d'échec de validation du challenge est de 5 par heures (par adresse IP et utilisateur enregistré par email) ; -Si vous échouez 5 fois à valider le challenge DNS, on peut penser qu'il suffit d'attendre 1h, sauf qu'en fait non. Le « bannissement » est pour 1 semaine ! \ No newline at end of file +Si vous échouez 5 fois à valider le challenge DNS, on peut penser qu'il suffit d'attendre 1h, sauf qu'en fait non. Le « bannissement » est pour 1 semaine !