Let's encrypt : certificat multi domaines

Bonjour à tous,

Un petit article rapide sur comment avoir un certificat Let's Encrypt qui couvre plusieurs domaines comme c'est le cas sur mon site : boris-tassou.fr et www.boris-tassou.fr.

Tout d'abord, il est nécessaire de générer une clé qui servira pour la création et l'enregistrement du compte auprès de Let's Encrypt :

openssl genrsa 4096 > account.key

Il faut maintenant générer la clé qui sera utilisée pour le ou les certificats LE que vous génèrerez :

openssl genrsa 4096 > boris-tassou.key

On peut donc passer à la génération du CSR multi-domains. Dans ce cas précis, je n'ai que deux domaines mais il est possible d'en avoir plus si vous souhaitez couvrir d'autres domaines avec le même certificat (même si ce n'est pas la technique la plus propre) :

openssl req -new -sha256 -key boris-tassou.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:boris-tassou.fr,DNS:www.boris-tassou.fr")) > boris-tassou.csr

Avant de pouvoir enregistrer le CSR et d'obtenir le certificat auprès de LE, il faut configurer le virtual host, dans mon cas avec Nginx :

server {
        listen   80;
        listen [::]:80 ipv6only=on;
        server_name     boris-tassou.fr www.boris-tassou.fr;
        location /.well-known/acme-challenge/ {
                        alias /usr/local/www/challenges/;
			try_files $uri =404;
        }
}

Il est simpliste et ne gère pas le HTTPS pour l'instant car LE doit pouvoir accéder au challenge qu'il génère.

Pour l'enregistrement au près de LE, j'utilise le script python acme_tiny que vous pouvez trouver ici : https://github.com/diafygi/acme-tiny

Pour avoir le certificat signé, il faut exécuter la commande suivante :

python3 /etc/ssl/LE/acme_tiny.py --account-key /etc/ssl/LE/account.key --csr /etc/ssl/LE/domain.csr --acme-dir /usr/local/www/challenges/ > /etc/ssl/LE/signed_chain.crt || exit

Votre certificat est maintenant disponible!

Il ne reste plus qu'à modifier le virtual host pour gérer le HTTPS tout en laissant la possibilité à LE de pouvoir accéder au challenge pour le renouvellement du certificat :

server {
        listen   80;
        listen [::]:80 ipv6only=on;
        server_name     boris-tassou.fr www.boris-tassou.fr;
	location /.well-known/acme-challenge/ {
                        alias /usr/local/www/challenges/;
			try_files $uri =404;
        }

	location / {
        	return 301 https://$server_name$request_uri;
	}
}

server {
        listen 443 ssl;
        listen [::]:443 ssl ipv6only=on;
        server_name     www.boris-tassou.fr boris-tassou.fr;

        if ($host = 'boris-tassou.fr' ) {
                rewrite  ^/(.*)$  https://www.boris-tassou.fr/$1  permanent;
        }

        access_log /var/log/blog/access.log;
        error_log /var/log/blog/error.log;

        include /usr/local/etc/nginx/ssl.conf;

        ssl_certificate /etc/ssl/LE/signed_chain.crt;
        ssl_certificate_key /etc/ssl/LE/boris-tassou.key;

        client_max_body_size 10m;

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://XXXXXXXXX;
    }
}

Afin d'avoir une utilisation complète du certificat, je publie l'empreinte de la clé publique pour éviter une usurpation du certificat.
Pour récupérer cette empreinte, il faut exécuter la commande suivante :

openssl x509 -in /etc/ssl/LE/signed_chain.crt -noout -pubkey | openssl pkey -pubin -outform DER | sha512

Il ne reste plus qu'à l'ajouter au DNS, dans mon cas Knot :

_443._tcp.www.boris-tassou.fr. TLSA 3 1 2 EMPREINTETLSA

Les options de la déclaration du TLSA peuvent varier :

  • TLSA 3 0 2 : si le certificat ne change pas, hors il change quand il est renouvellé (publication de l'empreinte du certificat).
  • TLSA 3 1 2 : si le certificat change mais que la clé privée ne change pas (publication de l'empreinte de la clé publique).

Pour gérer le renouvellement automatique (le certificat généré étant valide pour 90J), il faut mettre en place une tâche cron qui exécute ce petit script :

#!/bin/sh
python3 /etc/ssl/LE/acme_tiny.py --account-key /etc/ssl/LE/account.key --csr /etc/ssl/LE/boris-tassou.csr --acme-dir /usr/local/www/challenges/ > /etc/ssl/LE/signed_chain.crt || exit
service nginx reload

Et la tâche cron :

# s'execute une fois par mois
0 0 1 * * /root/renew_cert.sh 2>> /var/log/acme_tiny.log

Vous pouvez maintenant profiter des certificats Let's Encrypt!

Have a nice day.