Table des matières

Let's Encrypt avec nginx

Let's Encrypt” permet de créer des certificats “SSL/https” gratuitement , et surtout, reconnu par la grande majorité des navigateurs.

:!: UPDATE: La suite logiciel du client “Let's Encrypt” a changé de nom pour “certbot”.

Il y a quelques limites (susceptible de changer), dont:

Pour ce qui concerne les limites, on peut quand même faire des tests à volonté avec des “fausses clés”… ouf.

Il y a 2 gros écueils:

  1. Il faut pouvoir être identifié “automagicaly” comme administrateur des domaines
  2. Il faut renouveler les certificats relativement souvent (<90 jours).

Je vais rapidement expliquer comment installer les outils “Let's Encrypt” et puis les utiliser.

J'ai pour habitude d'utiliser nginx en frontal https, comme proxy… Donc, la mise en pratique reposera sur nginx, mais c'est parfaitement adaptable pour d'autres environnements…

Dans un autre article , j'explique comment faire signer ses propres clés…
(Et c'est finalement cette dernière méthode que j'ai adopté pour ma petite infra perso…)

~~READMORE~~

Installation

L'installation va se faire sur notre serveur nginx.

Pré-requis: Installer le package git .

Installer les sources:

$ cd /usr/local/src
$ git clone https://github.com/letsencrypt/letsencrypt

Allez dans le répertoire d'installation:

$ cd letsencrypt

Devenez root.

$ su

Demarrer le script “letsencrypt-auto”.

# ./letsencrypt-auto --help

Si rien de bizarre (en dehors de l'affichage de l'aide) ne se passe, alors c'est bon: Pas de problème de dépendance.

Pour finir, on créé un lien symbolique pour que ce script soit accessible de partout.

# ln -s /usr/local/src/letsencrypt/letsencrypt-auto /usr/local/bin/
:!: Voir a la fin comment mettre à jour le script “letsencrypt-auto

nginx

Il y a plusieurs manières d'obtenir des clés signés, et la principale difficulté, c'est d'être identifier comme l'administrateur des serveurs sur lesquels pointent les domaines.

La méthode qu'on va utiliser consiste a préparer chaque domaine pour recevoir des requêtes sur le port 80 (oui!) , et puis laisser ouvert le chemin absolu suivant:
/.well-known/acme-challenge/

C'est ainsi, que pour chaque domaine, “Let's Encrypt” va être en mesure de valider le processus de création des certificats.

Dans nginx, pour un serveur quelconque je vais faire:

server {
  listen 80;

  server_name <domain1>
              <domain2>
              <domain3>
              ;

  location /.well-known/acme-challenge/ {
    root /var/www/letsencrypt-challenge/;
    #autoindex on;
  }  

  location / {
    return 301 https://$host;
  }

}

Bien sur, “<domain1>” “<domain2>” et “<domain3>” correspond a vos domaines. Par exemple, pour moi:

www.eez.fr
reload.eez.fr
webmail.tjaouen.fr

Je vais aussi créer le répertoire pour recevoir les identifiants:

# mkdir -p /var/www/letsencrypt-challenge/.well-known/acme-challenge/
:!: UPDATE: j'ai remarqué que le répertoire “acme-challenge” était supprimé par “letsencrypt-auto”, mais ça ne semble pas avoir d'incidence sur la suite.

Redémarrer nginx :

# service nginx configtest
# service nginx reload
:!: On verra la partie “https” de nos domaines un peu plus loin

Tester à partir d'un autre réseau:

$ curl -I http://<domain1>/.well-known/acme-challenge/
HTTP/1.1 404 Not Found
...

C'est une erreur attendue: Il n'y a pas de fichier (à moins d'activer “autoindex on” …).

Composer une configuration pour LE

On peut trouver plusieurs manières de générer les clés en tapant tout en ligne de commande, mais je préfère mettre tout dans un fichier de configuration, un “.ini”.

Par exemple, je créé un fichier “domain1.ini” contenant:

# ---------------------------------
rsa-key-size = 2048
domains = <domain1>, <domain2>, <domain3>
# ------------
email = noreply@eez.fr
authenticator = webroot
webroot-path = /var/www/letsencrypt-challenge
text = true
non-interactive = true
agree-tos = true
no-self-upgrade = true
# ------------
#staging = true
#quiet = true
# ---------------------------------
# More: letsencrypt-auto --help all
# ---------------------------------
# EOF

Adapter comme vous voulez, mais:

:!: je vous conseille d'abord de décommenter la ligne “staging = true

Avec “staging = true” , les clés fonctionneront mais ne seront pas signés par l'authorité qui va bien: Vous n'aurez pas le cadenas tout vert.
Par contre, il n'y a pas de limites: c'est mieux pour tester :-)

Créer les clés

Maintenant, il suffit juste de dire qu'on veut un certificat:

# letsencrypt-auto certonly --config domain1.ini

Checking for new version...
Requesting root privileges to run letsencrypt...
   /root/.local/share/letsencrypt/bin/letsencrypt certonly --config domain1.ini

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/domain1/fullchain.pem. Your cert
...

Le résultat apparait dans “/etc/letsencrypt/live/<domain1>/” :

On peut examiner le contenu d'un des certificats:

# openssl x509 -in /etc/letsencrypt/live/<domain1>/cert.pem -noout -text
...
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Fake LE Intermediate X1
        Validity
            Not Before: Jan  8 18:13:00 2016 GMT
            Not After : Avr  7 18:13:00 2016 GMT
        Subject: CN=<domain1>
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
...
            X509v3 Subject Alternative Name: 
                DNS:<domain1>, DNS:<domain2>
...

Le champ “Issuer” nous indique que c'est un “Fake”: c'est bien ce qu'on a voulu avec “staging = true”.

S'il vous prend l'envie de relancer la même commande, voici ce qui arrive:

# letsencrypt-auto certonly --config domain1.ini 
Checking for new version...
Requesting root privileges to run letsencrypt...
   /root/.local/share/letsencrypt/bin/letsencrypt certonly --config domain1.ini

-------------------------------------------------------------------------------
Certificate not yet due for renewal; no action taken.
-------------------------------------------------------------------------------

Un test est fait, et les clés ne sont ni recréées, ni renouvelées.

Si vous voulez absolument forcer la génération de nouvelles clés, alors ajouter l'option:

--force-renewal

FIXME: Si j'ai bien compris, a partir du 10 ieme jour avant la fin de la validité des clés, les certificats sont renouvelable, sans besoin de rajouter “--force-renewal”.

On remarquera que les sous répertoire à partir de “/etc/letsencrypt” , se peuplent de plein d'autres fichiers…
Les configurations de chaque jeu de clés sont conservés.

Pour renouveller toutes les clés, pour toutes les configurations, il suffit de taper:

# letsencrypt-auto renew

Exemple:

# letsencrypt-auto renew
Checking for new version...
Requesting root privileges to run letsencrypt...
   /root/.local/share/letsencrypt/bin/letsencrypt renew

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/domain1.conf
-------------------------------------------------------------------------------

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/domain1/fullchain.pem (skipped)

Évidemment, les clés ne sont pas renouvelés puisqu'elles sont trop loin de la date d'expiration.

nginx et https

Revenons dans la conf de nginx:
On est maintenant en possession de clés et on va déclarer l'accès https pour nos domaines.
On va ajouter ceci dans notre configuration (exemple) :

server {
  listen 443 ssl;

  server_name <domain1>
              <domain2>
              <domain3>
              ;

  # OCSP Stapling
  # fetch OCSP records from URL in ssl_certificate and cache them
  ssl_stapling_verify on;
  ssl_stapling on;

  ssl_trusted_certificate /etc/letsencrypt/live/domain1/chain.pem;
  ssl_certificate /etc/letsencrypt/live/domain1/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/domain1/privkey.pem;

  # ... etc ...
    
}
:!: Rappel: on a créé des “fausses” clés jusqu'a présent

Vous devez être en mesure de tester que ça fonctionne.

Pour créer de vrais clés, il suffit de commenter l'option “staging = true” et de forcer un renouvellement des clés.

Renouvellement automatique

Renouveler les clés n'est pas trop un problème: il suffit de mettre dans un CRON:

@daily letsencrypt-auto renew >/dev/null

Mais en pratique, ça ne suffit pas, car il faut aussi redémarrer les services qui utilisent ces clés.

Une solution

On peut utiliser l'option “--renew-hook=SCRIPT” pour signaler qu'il y a de nouvelles clés…

Pour le cas de nginx , on peut composer un petit script nommé “le_renew.sh”, dans “/usr/local/bin” :

#!/bin/sh

PATH=$PATH:/usr/sbin:/usr/local/bin

letsencrypt-auto renew --renew-hook 'touch /var/run/le_renew'

if rm /var/run/le_renew >/dev/null 2>&1 ; then
  service nginx configtest && service nginx reload
fi

exit 0

Rendre ce script éxécutable :

# chmod a+x le_renew.sh

Et puis ajouter dans le CRON ( crontab -e ) :

@daily [ -x /usr/local/bin/le_renew.sh ] && /usr/local/bin/le_renew.sh >/dev/null

Divers

Mise à jour du script letsencrypt-auto

:!: UPDATE: 2016/05/31

Dans la suite, je vais bloquer les mises à jour automatique de “Let's Encrypt” afin de les contrôler… J'aime pas les M-A-J sans mon accord :-)

Pour mettre a jour , il faudra retourner dans “/usr/local/src/letsencrpyt” et faire:

# cd /usr/local/src/letsencrypt

Et puis (par exemple):

# ./letsencrypt-auto --version

Et puis, “oh!”, une mise à jour:

Checking for new version...
Upgrading letsencrypt-auto 0.5.0 to 0.7.0...
Replacing letsencrypt-auto...
   cp -p ./letsencrypt-auto /tmp/tmp.29OFeZ6yPt/letsencrypt-auto.permission-clone
   cp /tmp/tmp.29OFeZ6yPt/letsencrypt-auto /tmp/tmp.29OFeZ6yPt/letsencrypt-auto.permission-clone
   mv -f /tmp/tmp.29OFeZ6yPt/letsencrypt-auto.permission-clone ./letsencrypt-auto
letsencrypt 0.7.0

Si la mise à jour n'est pas controlée, le lien symbolique dans “/usr/local/bin/letsencrypt-auto” risque de sauter.

Donc, moi, perso, oui moi je, je conseille de (re)faire:

# ln -sf /usr/local/src/letsencrypt/letsencrypt-auto /usr/local/bin/

Conclusion

Je reviendrais faire un petit bilan dans quelques mois :-)