Automatiser le renouvellement LetsEncrypt (http-01)

LetsEncrypt c'est le bien. C'est tellement bien qu'on l'utilise même pour le site que vous visitez actuellement. Si si, la preuve :

Le soucis avec LetsEncrypt, c'est que les certificats sont valides 90 jours (environ 3 mois). C'est assez long pour ne pas être un problème, mais la tâche est assez fastidieuse : il faut créer des fichiers/dossiers, et si le certificat comporte plusieurs domaines, voire plusieurs dizaines (coucou Epicube et ses 60 noms), c'est vite énervant. [Je suis un développeur, j'en ai eu marre dès le second sous-domaine]

La solution ? Se tourner vers des solutions alternatives, ou les développer soi même.

Aujourd'hui je vais donc vous présenter simp_le. C'est mon préféré pour http-01. Pourquoi ? Tout simplement parce qu'il permet de créer automatiquement les fichiers de LetsEncrypt dans le bon dossier et effectue la validation tout seul. Il est juste assez verbeux, et s'intègre facilement dans des scripts.

Dans trois mois, ce ne sera sans doute plus mon favori. dns-01, tls-sni-01 et proofOfPossession-01 remplaceront http-01. Que dis-je ?! dns-01 vaincra !

La configuration nginx sur ungeek.fr ressemble à ceci :

sl_certificate_key /etc/nginx/key.pem;  
ssl_certificate /etc/nginx/fullchain.pem;  
server {  
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name ungeek.fr;
        location /.well-known/acme-challenge/ {
                alias /var/www/.well-known/acme-challenge/;
        }
        return 301 https://$server_name$request_uri;
}

server {  
        listen 443 default_server http2 ssl;
        server_name ungeek.fr;

        location / {
                proxy_pass http://ghost;
        }
}

Les certificats sont dans /etc/nginx/, et seul /.well-known/acme-challenge/ est accessible sur le port 80 (http). Les autres requêtes sont redirigées.

Les avantages de cette configuration : HTTPS est forcé, les requêtes du port 80 sont légères (statiques ou redirigées) et elle permet de valider tous les domaines de manière centralisée : toutes les preuves LetsEncrypt iront dans /var/www/.well-known/acme-challenge/.

L'alias redirige vers /var/www/.well-known/acme-challenge/, on devra donc dire à simp_le que la racine du site est /var/www/.

Installation de simp_le

Malheureusement, cette étape n'est pas simple :'(
Il faut obtenir le code de simp_le, installer les dépendances et le rendre executable.

# Cloner
$ cd /opt
$ apt install git # Au cas où :D
$ git clone https://github.com/kuba/simp_le
Cloning into 'simp_le'...  
remote: Counting objects: 499, done.  
remote: Total 499 (delta 0), reused 0 (delta 0), pack-reused 499  
Receiving objects: 100% (499/499), 251.34 KiB | 0 bytes/s, done.  
Resolving deltas: 100% (294/294), done.  
Checking connectivity... done.  
$ cd simp_le

# Installation
$ ./bootstrap.sh
# Beaucoup de lignes ...
$ ./venv.sh
# Encore plus de lignes
$ ln -s $(pwd)/venv/bin/simp_le /usr/local/sbin/simp_le

Afin de simplifier cet article, je ne vous apprends pas à créer un utilisateur simp_le qui aura juste assez de droits pour créer les dossiers dans /var/www/ et dans /etc/nginx. (C'est bien d'écrire, on choisit le contenu !)

On vérifie que ça fonctionne:

$ simp_le
You must set at least one -d/--vhost

Debugging tips: -v improves output verbosity. Help is available under --help.  

Ouf, ça fonctionne !

Mise en place de notre script 8)

Le script est assez simple : une fois que vous savez manipuler simple, il suffit de mettre la commande dans un fichier nommé /usr/local/bin/renewssl.sh (par exemple). Dans mon cas, ceci suffit :

#!/bin/bash
cd /etc/nginx/  
simp_le -v -d ungeek.fr:/var/www -d www.ungeek.fr:/var/www \  
-f key.pem -f fullchain.pem -f account_key.json \
&& systemctl reload nginx

Si vous voulez ajouter plusieurs domaines, il suffit de mettre autant de -d ungeek.fr:/dossier/du/site que nécessaire. Et si vous en avez plein et qu'ils suivent un motif, vous pouvez même écrire un script qui fait ça pour vous ! :D

On l'exécute une première fois pour avoir la sortie console :

$ chmod +x /usr/local/bin/renew_ssl.sh
$ /usr/local/bin/renew_ssl.sh
2016-01-30 01:36:12,726:DEBUG:simp_le:1317: ['-v', '-d', 'ungeek.fr:/var/www', '-f', 'key.pem', '-f', 'fullchain.pem', '-f', 'account_key.json'] parsed as Namespace(account_key_public_exponent=65537, account_key_size=4096, cert_key_size=4096, default_root=None, email=None, integration_test=False, ioplugins=['key.pem', 'fullchain.pem', 'account_key.json'], reuse_key=False, revoke=False, server='https://acme-v01.api.letsencrypt.org/directory', test=False, tos_sha256='33d233c8ab558ba6c8ebc370a509acdded8b80e5d587aa5d192193f35226540f', user_agent='simp_le/0', valid_min=2592000, verbose=True, vhosts=[Vhost(name='ungeek.fr', root='/var/www')])  
2016-01-30 01:36:12,727:DEBUG:simp_le:314: Loading key.pem  
2016-01-30 01:36:12,728:DEBUG:simp_le:314: Loading fullchain.pem  
2016-01-30 01:36:12,728:DEBUG:simp_le:314: Loading account_key.json  
2016-01-30 01:36:12,728:DEBUG:simp_le:1234: Computed roots: {'ungeek.fr': '/var/www'}  
2016-01-30 01:36:12,728:INFO:simp_le:1158: Generating new account key  
... ... ...
2016-01-30 01:36:20,842:INFO:simp_le:338: Saving key.pem  
2016-01-30 01:36:20,842:INFO:simp_le:338: Saving fullchain.pem  
2016-01-30 01:36:20,845:INFO:simp_le:338: Saving account_key.json  

Hoora ! (J'espère pour vous ;D)

Ensuite, on ajoute une instruction à cron afin qu'il l'execute tous les mois (c'est plus prudent) :

$ crontab -e
<imaginer un éditeur de texte ici>  

On ajoute cette ligne: 0 0 1 * * /usr/local/bin/renew_ssl.sh et on quite (Ctrl+X avec nano, bonne chance avec vim).

Et c'est tout. Vous pouvez vérifier que l'exécution se déroule bien en vous assurant que la date de renouvellement de votre certificat change (ou si votre site est inaccessible via HTTPS au bout de 90 jours :D)

Alternative intéressante: lego (qui supporte dns-01, ls-sni-01 et proofOfPossession-01. Oh oui, oh oui, oh oui ! <3)