[certbot][bind] DNS Challenge

L’objectif est de générer automatiquement ses certificats Let’s Encrypt avec Certbot. Le scénario est le suivant :

  • Certbot initie une demande

  • Let’s Encrypt initie le Request Challenge

  • Certbot met à jour la zone DNS pour répondre au défi

  • Certbot signale à Let’s Encrypt que l’enregistrement est en place

  • Let’s Encrypt vérifie l’enregistrement DNS

  • Let’s Encrypt délivre les nouveaux certificats

Prérequis

  • Avoir installé certbot

  • Avoir un serveur bind fonctionnel, le service est exécuté de préférence par un utilisateur spécifique, ex « bind ».

Un seul nom de clé pour commencer

Tester avec une seule clé nommée « tsig-key ».

Préparer le serveur DNS

Mise en place

Générer les clés et on s’assure que les fichiers sont lisibles par l’utilisateur bind.

tsig-keygen -a hmac-sha512 tsig-key > /etc/bind/tsig.key
tsig-keygen -a hmac-sha512 tsig-key > /etc/bind/rndc.key
chown bind: /etc/bind/tsig.key
chown bind: /etc/bind/rndc.key

Les clés générées sont au format suivant :

key "tsig-key" {
        algorithm hmac-sha512;
        secret "secret==";
};

Partie à ajouter dans named.conf.local :

include "/etc/bind/tsig.key";

zone "jbsky.fr" IN {
        update-policy {
                grant tsig-key name _acme-challenge.www.jbsky.fr. TXT;
                grant tsig-key name _acme-challenge.mail.jbsky.fr. TXT;
        };
        type master;
        file "/etc/bind/db.jbsky.fr";
};

Vérifier que la mise à jour fonctionne

On test la commande suivante en local afin de vérifier si la mise à jour fonctionne.

KEYFILE=/etc/bind/tsig.key
nsupdate -d -k $KEYFILE <<EOT
server ns1.jbsky.fr
zone jbsky.fr.
update add _acme-challenge.mail.jbsky.fr. 10 txt yellow
send
EOT

dig TXT _acme-challenge.mail.jbsky.fr.

Brancher les scripts de défi

En suivant cette page https://certbot.eff.org/docs/using.html#pre-and-post-validation-hooks, il va nous falloir 2 scripts (auth et clean) afin que certbot met à jour par les « hooks » de son script les infos DNS demandées.

Les variables sont passées à chacun des 2 scripts par certbot:

CERTBOT_DOMAIN: The domain being authenticated
CERTBOT_VALIDATION: The validation string

/usr/local/bin/auth.sh

#!/bin/sh

keyfile=/etc/bind/tsig.key
server=127.0.0.1
domain=$(expr match "_acme-challenge.$CERTBOT_DOMAIN" '.*.(.*..*)')
echo "domain: $domain"
echo "trying : update add _acme-challenge.$CERTBOT_DOMAIN 60 txt $CERTBOT_VALIDATION"
nsupdate -d -k $keyfile <<EOT
server $server
zone $domain
update add _acme-challenge.$CERTBOT_DOMAIN 60 txt $CERTBOT_VALIDATION
send
EOT

Mise en place

/usr/local/bin/clean.sh

#!/bin/sh

keyfile=/etc/bind/tsig.key
server=127.0.0.1
domain=$(expr match "_acme-challenge.$CERTBOT_DOMAIN" '.*.(.*..*)')
echo "domain: $domain"
echo "trying : update del _acme-challenge.$CERTBOT_DOMAIN 60 txt"
nsupdate -d -k $keyfile <<EOT
server $server
zone $domain
update del _acme-challenge.$CERTBOT_DOMAIN 60 txt
send
EOT

Vérifier avant de publier

Passer la commande suivant en adaptant la valeur après le drapeau -d. –dry-run permet de faire un essai à sec –manual-public-ip-logging-ok permet de passer la question si vous souhaitez être loggué

certbot certonly --preferred-challenges=dns  --manual-auth-hook /usr/local/bin/auth --dry-run --manual-cleanup-hook /usr/local/bin/cleanup -d mail.jbsky.fr -d www.jbsky.fr --manual --manual-public-ip-logging-ok
[...]
IMPORTANT NOTES:
 - The dry run was successful.

Si tout se passe bien « The dry run was successful », on peut enlever le l’option –dry-run et vérifier les certificats dans le répertoire /etc/letsencrypt/live.

Planifier le renouvellement

Commande suivante pour ouvrir crontab en mode édition

crontab -e

L essai a sec conditionne l emission reelle : si le premier echoue, le second ne part pas. C est ce qui evite de consommer un quota d emission sur une configuration cassee.

# Renouvellement quotidien des certificats deja emis
47 6 * * * root /usr/bin/certbot renew --quiet

# Deux fois par mois : essai a sec, puis emission reelle seulement s il reussit
0 0 8,22 * * root /usr/bin/certbot certonly --manual --preferred-challenges=dns \
    --manual-auth-hook /usr/local/bin/auth \
    --manual-cleanup-hook /usr/local/bin/cleanup \
    -d www.exemple.fr -d mail.exemple.fr --dry-run > /dev/null 2>&1 \
  && /usr/bin/certbot certonly --manual --preferred-challenges=dns \
    --manual-auth-hook /usr/local/bin/auth \
    --manual-cleanup-hook /usr/local/bin/cleanup \
    -d www.exemple.fr -d mail.exemple.fr > /dev/null 2>&1

Deux erreurs qui coûtent du temps

Mauvais format de clé

Attention, générer la clé avec la commande suivante ramène l’erreur « TSIG error with server: tsig indicates error » ou encore dans le syslog « tsig verify failure (BADKEY) »

dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST _acme-challenge.mail.jbsky.fr

En effet, en testant avec la commande suivante, le serveur ne traite pas avec ce type de clé. Il semblerait que cela soit « deprecated ».

KEYFILE=/dnskey/K_acme-challenge.mail.jbsky.fr.+157+20343.
nsupdate -d -k $KEYFILE <<EOT
server ns1.jbsky.fr
zone jbsky.fr.
update add _acme-challenge.mail.jbsky.fr. 10 txt yellow
send
EOT

Pas de droit d’écriture

Côté serveur Bind, s’assurer que l’utilisateur bind peut écrire dans son répertoire /etc/bind/

chown bind: /etc/bind

Liens

Articles connexes