Dans cet article, on va configurer dehydrated.io pour produire des certificats ECDSA pour HAProxy, sans passer par un reload
ou restart
du service.
Configuration de dehydrated
Dehydrated est assez simple à configurer : il suffit de lister les domaines pour lesquels on veut générer un certificat dans /etc/dehydrated/domains.txt
.
Ensuite, il faut s’enregistrer auprès de Let’s Encrypt :
sudo dehydrated --register --accept-terms
Il faut également modifier /etc/dehydrated/config
pour
- définir l’emplacement des fichiers pour le challenge ACME
- créer des clés ECDSA
Le fichier de configuration doit donc être modifier ainsi :
CONFIG_D=/etc/dehydrated/conf.d
BASEDIR=/var/lib/dehydrated
WELLKNOWN="/var/www/dehydrated"
DOMAINS_TXT="/etc/dehydrated/domains.txt"
HOOK=${BASEDIR}/hook.sh
KEY_ALGO=secp384r1
Ce qui est important ici, c’est WELLKNOWN
, qui définit l’emplacement des challenges, HOOK
, qui nous servira plus tard pour lier dehydrated à HAProxy, et KEY_ALG
, pour passer en ECDSA.
On ne générera pas les certificats tout de suite, il faut d’abord mettre la “colle” entre HAProxy et Dehydrated.
Configuration de NGinX
HAProxy n’étant pas capable de servir des fichiers (c’est un reverse-proxy après tout), il nous faut un serveur web. Bien sûr le lecteur est libre d’utiliser celui qu’il veut, mais dans ce billet je ne vais couvrir que NGinX.
La définition du serveur est relativement simple, il faut juste servir /var/www/dehydrated
sous l’arborescence /.well-known/acme-challenge/
, en utilisant un autre port que 80 ou 443.
server {
listen *:54321;
root /var/www;
error_log /var/www/error;
location ^~ /.well-known/acme-challenge {
alias /var/www/dehydrated;
}
}
Configuration de HAProxy
Tout d’abord, il faut s’assurer qu’on a bien activé la socket d’administration si on veut pouvoir changer les certificats à chaud.
Dans /etc/haproxy/haproxy.cfg
:
global
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
Toutes les options ne sont pas forcément nécessaires mais la socket doit a minima être de niveau admin
Ensuite, il reste la question de comment sont déclarés les certificats dans notre directive bind
.
- Cas 1: un seul certificat
- Dans ce cas, aucune précaution n’est à prendre.
- Cas 2: plusieurs certificats
- Si vous avez plusieurs certificats, il va être nécessaire, pour que tout fonctionne comme attendu, que vous utilisiez un répertoire pour les stocker et les appeler, plutôt que de les lister individuellement.
bind *:443 ssl crt /etc/haproxy/ssl-certs/
- Ainsi, HAProxy chargera tous les certificats de ce dossier.
Il faut également créer le nécessaire pour que HAProxy route les requêtes sur /.well-known/acme-challenge/
vers notre serveur NGinX.
Il va aussi falloir ajouter une exception à nos directive http-request redirect
, entre autres, pour ne pas interférer avec les challenges :
frontend fe_main
...
acl letsencrypt-acl path_beg /.well-known/acme-challenge/
...
# Redirection de HTTP vers HTTPS
http-request redirect scheme https code 301 if !{ ssl_fc } !letsencrypt-acl
...
# Attention à bien placer ce use_backend AVANT tous les autres
use_backend letsencrypt if letsencrypt-acl
...
backend letsencrypt
server nginx 127.0.0.1:54321
Hook dehydrated
Dehydrated est un script bash, et permet d’injecter des fonctions via un script dans /var/lib/dehydrated/hook.sh
. Nous allons nous en servir pour injecter les certificats dans HAProxy, via sa socket d’administration.
Les commandes sont :
new ssl cert <fichier de certificat>
pour créer un certificat (dans le cas d’un nouveau certificat)set ssl cert <fichier de certificat> <<\n<clé et certificat au format PEM>
pour définir le contenu du certificatcommit ssl cert <fichier de certificat>
pour terminer la transactionadd ssl crt-list <répertoire des certificats> <fichier de certificat>
pour attacher le certificat à notrefrontend
(dans le cas d’un nouveau certificat)
Dehydrated fournit un squelette de fichier hook.sh
dans /usr/share/doc/dehydrated/examples/hook.sh
, on va le copier sous /var/lib/dehydrated/hook.sh
et modifier la fonction deploy_cert()
:
deploy_cert() {
local DESTINATION="/etc/haproxy/ssl-certs"
local FULLCERTFILE="${DESTINATION}/${DOMAIN}.pem"
local HAPSOCKET="/run/haproxy/admin.sock"
echo " + Deploying cert ${FULLCERTFILE}"
# Update cert in RAM
if ! [[ -f "${FULLCERTFILE}" ]]; then
echo "new ssl cert ${FULLCERTFILE}" | socat stdio $HAPSOCKET
echo -e "set ssl cert ${FULLCERTFILE} <<\n$(sed /^$/d "${KEYFILE}" "${FULLCHAINFILE}")\n" | socat stdio $HAPSOCKET
echo "commit ssl cert ${FULLCERTFILE}" | socat stdio $HAPSOCKET
echo "add ssl crt-list ${DESTINATION} ${FULLCERTFILE}" | socat stdio $HAPSOCKET
else
echo -e "set ssl cert ${FULLCERTFILE} <<\n$(sed /^$/d "${KEYFILE}" "${FULLCHAINFILE}")\n" | socat stdio $HAPSOCKET
echo "commit ssl cert ${FULLCERTFILE}" | socat stdio $HAPSOCKET
fi
# Update cert on disk
cat "${KEYFILE}" "${FULLCHAINFILE}" > "${FULLCERTFILE}"
}
Vous pouvez directement télécharger le script complet.
Il ne nous reste plus qu’à générer nos certificats :
sudo dehydrated -c
En cas de pépin, vous pouvez me trouver sur Mastodon