Quand on cherche à passer sur un certificat wildcard (en gros passer d'un certificat pour un domaine truc.exemple.com à *.exemple.com, de sorte à pouvoir utiliser le même certificat pour tous ses sous domaines (truc.exemple.com, bidule.exemple.com, chose.exemple.com, etc.)) via Let's Encrypt, on se retrouve obligé d'utiliser le challenge DNS-01 pour prouver qu'on a la main sur le serveur DNS.

Dans le cas de ce blog (et d'autres services privés que j'héberge sur le même serveur), le domaine est géré par un serveur BIND. J'ai donc pu automatiser un peu tout assez facilement.

Le fonctionnement général du challenge DNS-01

Dans les grandes lignes c'est assez simple. On cherche à valider que le demandeur du certificat contrôle bien le domaine (de sorte que n'importe quel personne mal intentionné ne puisse pas révoquer vos certificats ou créer d'autres certificats pour se faire passer pour vous). Pour celà, le serveur let's encrypt va nous demander d'enregistrer une chaîne de caractère aléatoire en face d'un domaine (_acme-challenge.example.com).

Ensuite le serveur va faire une requête DNS sur votre serveur pour valider qu'il donne bien cette chaîne de caractère. Si c'est le cas il vous délivrera un nouveau certificat.

Comme ce n'est pas très pratique de faire cette manipulation à la main, même si on pourrait le faire en répétant la manipulation tous les 3 mois, on peut automatiser tout ça.

À noter qu'ici comme je gère mon nom de domaine moi même, j'utiliserai le plugin dns-rfc2136 de certbot, et que la méthode peut être un peu différente pour d'autres gestionnaires de nom de domaine.

Générer un clé TSIG

La première étape est de générer une clé TSIG. Cette clé servira à certbot (ou le client let's encrypt de votre choix) pour s'authentifier sur votre serveur DNS pour ajouter la chaîne de caractère indiqué par le serveur let's encrypt.

La doc let's encrypt indique pour celà la commande suivante :

dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST keyname.

Mais pas de chance, cette commande ne fonctionne plus car elle est dépréciée[1] :

  1. [func] The use of dnssec-keygen to generate HMAC keys is deprecated in favor of tsig-keygen. dnssec-keygen will print a warning when used for this purpose. All HMAC algorithms will be removed from dnssec-keygen in a future release. [RT #42272]

Il faut maintenant utiliser cette commande :

tsig-keygen -a hmac-sha512 tsig-key > ./tsig.key

Concrètement, ça devrait vous générer un fichier qui ressemble à ceci :

key "keyname." {
	algorithm hmac-sha512;
	secret "iijJsbjqZmdB4ql0/wM/6ifxiDpe9QDRebwIZUNhhHonwj9UY+rSdnVuZNH9u0E2Xj6Gu1DyfNQpKq2WYGk82Q==";
};

À noter qu'on peut remplacer keyname. par le nom qu'on veut, c'est un peu comme le login qui sera utilisé par let's encrypt pour éditer votre configuration BIND à chaud. J'ai d'ailleurs changé ce nom dans mon cas 😉

Le fichier généré contient en fait un bloc de configuration pour BIND. Donc on a juste à le copier coller dans la configuration de BIND. Chez moi ce fichier est /etc/named.conf.

Autorisé la modification TXT pour certbot

Je ne rentre pas dans le détail de la création d'un nouveau domaine avec BIND. Dans mon cas je suis passé j'ai juste eu à ajouter un bloc update-policy à mon bloc zone. Ce qui donne quelque chose comme ça dans mon /etc/named.conf :

zone "exemple.com" IN {
    type master;
    file "exemple.com.zone";
    update-policy {
        grant keyname. name _acme-challenge.exemple.com. txt;
    };
};

Faites bien attention à bien indiquer à la place de keyname. le même nom que pour le nom de la clé TSIG, sinon ça ne fonctionnera pas.

À noter qu'il n'y a pas besoin de définir le sous domaine _acme-challenge dans notre zone.

On pourrait configurer en donnant plus de droit, mais le mieux c'est cette solution qui donne à certbot uniquement l'autorisation de modifier les éléments txt associé à un domaine très précis (qu'on utilise que pour la génération des certificats).

Pensez bien à redémarrer BIND pour que la config soit prise en compte. Chez moi un petit systemctl restart named.

Demander un nouveau certificat

Ici je traite uniquement la migration vers un domaine wildcard, donc je ne détaille pas toute la configuration certbot. Mais je suis passé de cette commande :

certbot certonly -n -w /var/www/letsencrypt \
    --agree-tos --rsa-key-size 2048 \
    -m katsuo49@somewhere.fr --cert-name k49 \
    -d exemple.com -d truc.exemple.com \
    -d bidule.exemple.com -d chose.exemple.com \
    -d chouette.exemple.com

à cette commande :

certbot certonly -n -w /var/www/letsencrypt \
    --agree-tos --rsa-key-size 2048 \
    -m katsuo49@somewhere.fr --cert-name k49 \
    --dns-rfc2136 \
    --dns-rfc2136-credentials ~/certbot-rfc2136.ini \
    -d exemple.com -d *.exemple.com

qui utilise donc un fichier certbot-rfc2136.ini (à modifier pour correspondre à votre configuration) :

# Target DNS server
dns_rfc2136_server = 192.168.0.1
dns_rfc2136_port   = 53
# TSIG key
dns_rfc2136_name = keyname.
dns_rfc2136_secret = iijJsbjqZmdB4ql0/wM/6ifxiDpe9QDRebwIZUNhhHonwj9UY+rSdnVuZNH9u0E2Xj6Gu1DyfNQpKq2WYGk82Q==
dns_rfc2136_algorithm = HMAC-SHA512

Si c'est votre première demande de certificat, un nouveau certificat sera créé, si vous aviez déjà un certificat, il sera renouvelé pour un certificat wilcard.

Conclusion

Je me suis un peu cassé la tête pour rien, j'ai lu milles doc avant de le faire alors que c'est vraiment tout simple en fait à mettre en place. Pensez juste à utiliser l'option de certbot --dry-run pour pouvoir tester votre configuration avant de lancer vraiment la génération et ne pas vous retrouver bloquer par la politique de sécurité de Let's Encrypt 😉

Maintenant à moi la joie des domaines wilcard ! 😀

Resources :

Crédit photo :
https://pixabay.com/photos/card-game-deck-letters-game-570835/


  1. https://gitlab.isc.org/isc-projects/bind9/commit/21761bfe799c8f298e3ce26285426b9a30473e6d?view=parallel ↩︎