Published: Mon 07 March 2016
By Sebastien Badia
In Tech .
tags: https letsencrypt
Voilà 1 million de certificats Let's Encrypt délivrés (les certificats délivrés par Let's Encrypt ); La littérature sur le sujet ne manque pas, mais je vais quand même en apporter une de plus, pour la partie compilation :-)
Pour rappel, Let's Encrypt, est un projet porté par l' « Internet Security Research Group » (ISRG), qui vise à automatiser, rendre accessible à tous, de manière ouverte et gratuite, des certificats SSL
Génération
Nous allons ici, ne pas utiliser le client officiel; principalement parce qu'il intègre trop de fonctionnalités (serveur web intégré, …), mais aussi parce qu'il ne répond pas vraiment aux besoins de cet article (arborescence flexible, serveur nginx, …; et que c'est plus facile à lire un script de 200 lignes qu'un énorme client…)
Le client que nous allons utiliser est donc le acme-tiny (écrit en python). Lors de mes pérégrinations sur la toile (oui ok ça fait un peu vieillot, j'aurais pu dire « alors que je surfais sur le web », … :-D), je suis tombé sur ce script letsencrypt.sh . Le coté FQDN à un endroit, et le rechargement lorsque les AltNames changent sont des features appréciables. Après c'est du bash, donc comme vous voulez :)
Création des certificats
De mon coté, j'ai opté pour une arborescence de ce type (certificats générés dans un répertoire dédié, avec un utilisateur dédié).
$ mkdir -p /etc/letsencrypt/{ certs,challenges,csr,pem,private}
/etc/letsencrypt/
├── certs
├── challenges
├── csr
├── pem
└── private
Il suffit donc alors de :
Créer une clé pour le domaine en question
Créer une demande de signature (CSR) en y incluant les noms DNS alternatifs
Lancer le client (qui va se charger de créer un challenge) et signer si le challenge est ok.
Télécharger et concaténer le certificat obtenu avec le certificat intermédiaire de Let's Encrypt
Le challenge sert ici à ce que let's encrypt vérifie que nous contrôlons bien le
domaine pour lequel nous demandons un certificat. Il faut d'ailleurs ajouter à
la configuration du serveur web, l'endroit où seront stockés ces challenges.
location /.well-known/acme-challenge/ {
alias /etc/letsencrypt/challenges/gitoyen.net/ ;
try_files $uri = 404 ;
}
Côté certificat intermédiaire, ils sont disponibles sur le site de Let's Encrypt .
Bon donc du coup ça donne cela dans un mini-script (pas super beau…)
#!/bin/bash
# bootstrap letsencrypt
account = $1
cert = $2
dns = $3
mkdir -p /etc/letsencrypt/{ certs,challenges,csr,pem,private}
pushd /etc/letsencrypt
if [[ ! -f "./private/ ${ account } .key" ]] ; then
openssl genrsa 4096 > "./private/ ${ account } .key"
fi
if [[ ! -f ./pem/intermediate.pem ]] ; then
wget -O - https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > ./pem/intermediate.pem
fi
echo "##### ${ cert } #####"
if [[ ! -f "./private/ ${ cert } .key" ]] ; then
openssl genrsa 4096 > "./private/ ${ cert } .key"
fi
mkdir -p "./challenges/ ${ cert } "
openssl req -new -sha256 -key "./private/ ${ cert } .key" -subj "/" -reqexts SAN -config <( cat /etc/ssl/openssl.cnf <( printf "[SAN]\nsubjectAltName=%s" " ${ dns } " )) > "./csr/ ${ cert } .csr"
acme_tiny.py --account-key "./private/ ${ account } .key" --csr "./csr/ ${ cert } .csr" --acme-dir "/etc/letsencrypt/challenges/ ${ cert } /" > "./certs/ ${ cert } .crt"
cat "./certs/ ${ cert } .crt" ./pem/intermediate.pem > "./pem/ ${ cert } .pem"
popd
Qu'il suffit de lancer comme ceci (pour l'exemple je génère un certificate
gitoyen.net avec comme domaines gérés gitoyen.net et www.gitoyen.net (oui de la pub au passage))
$ bash bootstrap-letsencrypt.sh gitoyen gitoyen.net 'DNS:gitoyen.net,DNS:www.gitoyen.net'
##### gitoyen.net #####
Parsing account key...
Parsing CSR...
Registering account...
Already registered!
Verifying www.gitoyen.net...
www.gitoyen.net verified!
Verifying gitoyen.net...
gitoyen.net verified!
Signing certificate...
Certificate signed!
Plutôt cool non ? Il suffit alors d'adapter la configuration du serveur web, pour
prendre en compte ces certificats. Et passer tout en HTTPS ! (dans notre cas,
c'est un nginx en reverse proxy qui gère le SSL et forward en HTTP sur une IP
privée).
# Gitoyen
server {
server_name gitoyen.net planet.gitoyen.net ;
rewrite ^(.*) https:// $host$1 permanent ;
}
# Gitoyen SSL
# DNS:gitoyen.net,DNS:planet.gitoyen.net
server {
listen 443 ;
ssl on ;
client_max_body_size 20M ;
server_name gitoyen.net www.gitoyen.net ;
ssl_certificate /etc/letsencrypt/pem/gitoyen.net.pem ;
ssl_certificate_key /etc/letsencrypt/private/gitoyen.net.key ;
ssl_session_timeout 5m ;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 ;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA ;
ssl_session_cache shared:SSL:50m ;
ssl_prefer_server_ciphers on ;
ssl_dhparam /etc/letsencrypt/dh4096.pem ;
ssl_ecdh_curve secp384r1 ;
add_header Strict-Transport-Security max-age=15768000 ;
resolver 127 .0.0.1 ;
location /.well-known/acme-challenge/ {
alias /etc/letsencrypt/challenges/gitoyen.net/ ;
try_files $uri = 404 ;
}
location / {
proxy_pass http://10.41.1.143 ;
proxy_set_header Host $host ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Forwarded-Proto https ;
proxy_set_header X-Forwarded-Ssl on ;
}
}
Pour la génération du dhparams (4096 bits c'est bien)
openssl dhparam -out dh4096.pem 4096
Et vous voila donc avec une super config et du HTTPS automatisé, on peut aller
faire un tour sur imirhil pour un
check de la conf et bien sûr pour pouvoir briller en société…
Supervision
Bon c'est bien beau, mais avec tout ça les certificats sont valables que 90j
(oui mort à CertPatrol :-() mais pour le coup il va donc falloir superviser
tout cela.
Via Certificate Monitor
Si vous utilisez le sympa certificatemonitor (code source ) de Raymii, il suffit alors d'ajouter vos FQDN dans l'interface. Et ainsi recevoir une notification avant l'expiration de vos certificats.
Via Checkmk
Sinon si vous avez déjà une bonne veille supervision à base de nagios ou checkmk ou compatible, il suffit d'ajouter les checks via le script check_http
.
Dans la conf main.mk
de checkmk:
# /etc/checkmk/main.mk
legacy_checks = [
## Gitoyen
( ( "check-certificate!gitoyen.net", "Certificate Gitoyen - Letsencrypt", True), ['baloo.gitoyen.net']),
( ( "check-certificate!www.gitoyen.net", "Certificate www Gitoyen - Letsencrypt", True), ['baloo.gitoyen.net']),
]
Et ne pas oublier la check_command
associée (on émet un warning lorsque que le certificat expire à J-30 et un critical à J-7)
# /etc/checkmk/conf.d/commands_extra.mk
define command {
command_name check-certificate
command_line $USER1$/check_http -H $ARG1$ -C 30,7 --sni
}
Renouvellement
Il existe des scripts de renouvellement automatique:
Mais je ne sais pas encore quoi en penser, pour le moment je réagis lorsque que
le check passe en warning avec ce mini script bash.
#!/bin/bash
account = 'gitoyen'
certs = 'gitoyen.net www.gitoyen.net'
pushd /etc/letsencrypt
for cert in $certs
do
echo "##### ${ cert } #####"
acme_tiny.py --account-key ./private/gitoyen.key --csr ./csr/${ cert } .csr --acme-dir /etc/letsencrypt/challenges/${ cert } / > ./certs/${ cert } .crt
cat ./certs/${ cert } .crt ./pem/intermediate.pem > ./pem/${ cert } .pem
done
popd
systemctl restart nginx
Chocolat
Même si le modèle des CA est bancal, il n'y a plus de raison maintenant de ne pas proposer du HTTPS partout !