[Tuto] Certificat TLS avec Certbot pour BookMyName (FreeBSD)

cooper

Chevalier Jedi
Membre Confirmé
28 Octobre 2022
167
47
78
47
Ile-De-France
Professionnel
Non
Hello all,

Petit tutoriel sur la gestion (création/renouvellement) avec certbot d'un certificat TLS de letsencrypt.org chez le registrar BookMyName ayant le bon goût d'utiliser un BSD pour son Nas (ici FreeBSD) 😜

1. Objectif

Obtenir et renouveler automatiquement un certificat Let's Encrypt wildcard (*.example.net) + racine (example.net) en utilisant :
  • la méthode DNS-01 challenge,
  • les scripts adaptés pour BookMyName (bmn-auth.sh, bmn-cleanup.sh),
  • et l’infrastructure FreeBSD (periodic).

2. Installation et préparation

a. Installer Certbot et ses dépendances​

Bash:
pkg install py311-certbot

b. Installer les scripts suivants pour BookMyName​

1. Authentification puis enregistrement DNS TXT de l'empreinte :

Bash:
vi bmn-auth.sh
Bash:
#!/bin/sh
# bmn-auth.sh — ajout TXT BookMyName pour wildcard + domaine racine
# Vérification sur plusieurs DNS publics pour accélérer propagation
# Anti-warning : jamais exit 1

# ───────────────────────────────
# CONFIGURATION
# ───────────────────────────────
DNSSERVERS="8.8.8.8 1.1.1.1 9.9.9.9"  # Google, Cloudflare, Quad9
CURL_TIMEOUT=10

BMN_USER="USER" # Inclure les identifiants chez le registrar
BMN_PASS="PASS"

# ───────────────────────────────
# RACINE DOMAINE
# ───────────────────────────────
DOMAIN=$CERTBOT_DOMAIN
if [ "$(echo "$CERTBOT_DOMAIN" | awk -F. '{print NF}')" -gt 2 ]; then
    DOMAIN=$(echo "$CERTBOT_DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
fi

echo "──────────────────────────────────────────────"
echo "Auth hook for BookMyName"
echo "Domain: $CERTBOT_DOMAIN"
echo "Root:   $DOMAIN"
echo "Value:  $CERTBOT_VALIDATION"
echo "──────────────────────────────────────────────"

# ───────────────────────────────
# AJOUT DU TXT
# ───────────────────────────────
curl -s --max-time $CURL_TIMEOUT -u "$BMN_USER:$BMN_PASS" \
  "https://www.bookmyname.com/dyndns/?hostname=_acme-challenge.$DOMAIN&type=txt&ttl=300&do=add&value=\"$CERTBOT_VALIDATION\"" \
  | grep -q "good" && echo "TXT record creation requested" || echo "BookMyName update may have failed"

# ───────────────────────────────
# BUFFER INITIAL
# ───────────────────────────────
echo "Waiting 60s for initial propagation..."
sleep 60

# ───────────────────────────────
# VÉRIFICATION MULTI-DNS
# ───────────────────────────────
MAX_ATTEMPTS=60    # ~15 min
SLEEP_BETWEEN=15

attempt=0
record_visible=0

while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
    attempt=$((attempt + 1))
    echo "Checking attempt $attempt/$MAX_ATTEMPTS..."

    for ns in $DNSSERVERS; do
        public_val=$(drill _acme-challenge.$DOMAIN TXT @$ns 2>/dev/null | grep _acme | grep -v ";;" | awk '{print $5}' | tr -d '"')
        if [ "$public_val" = "$CERTBOT_VALIDATION" ]; then
            echo "Record visible on $ns after $((attempt * SLEEP_BETWEEN))s"
            record_visible=1
            break 2  # quitte les deux boucles
        fi
    done

    echo "Record not visible yet on any DNS"
    sleep "$SLEEP_BETWEEN"
done

if [ "$record_visible" -ne 1 ]; then
    echo "TXT record still not visible after $((MAX_ATTEMPTS * SLEEP_BETWEEN / 60)) minutes."
    echo "Let’s Encrypt can still validate the challenge if propagation occurs immediately afterward."
fi

# Ne jamais exit 1 pour éviter l’erreur dans Certbot
exit 0

2. Nettoyage des enregistrements DNS TXT:

Bash:
#!/bin/sh
# bmn-cleanup.sh — suppression automatique du TXT _acme-challenge pour BookMyName

BMN_USER="USER" # Inclure les identifiants chez le registrar
BMN_PASS="PASS"

DOMAIN=$CERTBOT_DOMAIN
if [ "$(echo "$CERTBOT_DOMAIN" | awk -F. '{print NF}')" -gt 2 ]; then
    DOMAIN=$(echo "$CERTBOT_DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
fi

echo "Removing TXT record for $CERTBOT_DOMAIN"
curl -s -u "$BMN_USER:$BMN_PASS" \
  "https://www.bookmyname.com/dyndns/?hostname=_acme-challenge.$DOMAIN&type=txt&ttl=300&do=remove&value=\"$CERTBOT_VALIDATION\"" \
  | grep -q "good" && echo "Cleanup done" || echo "Cleanup may have failed"
exit 0

Les placer dans /opt/local/bin/ (ou autre emplacement de son choix) :
Bash:
mv bmn-auth.sh /opt/local/bin/
mv bmn-cleanup.sh /opt/local/bin/
chmod 750 /opt/local/bin/bmn-*.sh

NB. Adaptation des scripts pour FreeBSD :
  • être compatible POSIX via #!/bin/sh
  • remplacer dig +short par une version compatible drill :
    drill _acme-challenge.$DOMAIN TXT @$DNSSERVER | grep _acme | grep -v ";;" | awk '{print $5}' | tr -d '"'

3. Première émission du certificat

Commande initiale (manuelle, une seule fois et remplacer example.net par son nom de domaine) :
Bash:
certbot certonly \
  --manual \
  --preferred-challenges=dns \
  --manual-auth-hook /opt/local/bin/bmn-auth.sh \
  --manual-cleanup-hook /opt/local/bin/bmn-cleanup.sh \
  -d '*.example.net' -d example.net \
  --agree-tos --email cert@example.net

Les fichiers générés :
Code:
/usr/local/etc/letsencrypt/live/example.net/
  ├── cert.pem
  ├── chain.pem
  ├── fullchain.pem
  └── privkey.pem

NB. Un seul certificat est créé pour les deux domaines (*.example.net + example.net).


4. Renouvellement automatique via periodic

FreeBSD fournit déjà un script :

/usr/local/etc/periodic/weekly/500.certbot-3.11

Il suffit de l’activer et de lui passer les bons arguments.

Configuration dans /etc/periodic.conf :​

Bash:
weekly_certbot_enable="YES"
weekly_certbot_custom_args="--no-random-sleep-on-renew --quiet"

# Redémarrage des services afin d'utiliser le nouveau certificat.
# Par exemple ici apache et unbound.
weekly_certbot_post_hook="service apache24 restart && service unbound restart"


NB. Option utile :
--no-random-sleep-on-renew
→ Désactive le délai aléatoire (jusqu’à 8h) inséré par défaut avant le renouvellement.

Comme periodic planifie déjà les exécutions (grâce à anticongestion de rc dans /usr/local/etc/periodic/weekly/500.certbot-3.11), c’est sûr de le désactiver.

Le renouvellement s'effectue par periodic et les paramètres de certbot renew sont enregistrés dans la configuration /usr/local/etc/letsencrypt/renewal/example.net.conf dont le contenu est le suivant :

Bash:
cat /usr/local/etc/letsencrypt/renewal/example.net.conf

version = 4.2.0
archive_dir = /usr/local/etc/letsencrypt/archive/example.net
cert = /usr/local/etc/letsencrypt/live/example.net/cert.pem
privkey = /usr/local/etc/letsencrypt/live/example.net/privkey.pem
chain = /usr/local/etc/letsencrypt/live/example.net/chain.pem
fullchain = /usr/local/etc/letsencrypt/live/example.net/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = XXXXXXXXXXXXXXX
pref_challs = dns-01,
authenticator = manual
manual_auth_hook = /opt/local/bin/bmn-auth.sh
manual_cleanup_hook = /opt/local/bin/bmn-cleanup.sh
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa


5. Vérification / Debug

Forcer un test de renouvellement :​

Bash:
certbot renew --dry-run


Historique :​

/var/log/letsencrypt/letsencrypt.log




6. Points clés

  • Les scripts bmn-*.sh gèrent l’ajout et la suppression des enregistrements DNS _acme-challenge chez BookMyName.
  • Le certificat couvre à la fois example.net et *.example.net.
  • Le renouvellement se fait automatiquement chaque semaine par periodic.
  • Après chaque renouvellement, Apache et Unbound sont redémarrés pour recharger le nouveau certificat.
  • Le paramètre --no-random-sleep-on-renew est désactivé pour un comportement déterministe.

NB. Les demandes de certificat(s) et de renouvellement via l'échange DNS-01 challenge prennent du temps eu égard à la propagation sur les serveurs DNS ; la durée de propagation varie suivant les registrars. Pour BookMyName, une fourchette entre 5 et 10 minutes pour que l'échange DNS-01 soit fait.


En résumé rapide

Elément​
Emplacement​
Commande​
Certificats/usr/local/etc/letsencrypt/live/example.net/
Script shell pour création/reno. du DNS TXT/opt/local/bin/bmn-auth.sh
Script shell pour nettoyage du DNS TXT/opt/local/bin/bmn-cleanup.sh
Configuration du renouvellement/usr/local/etc/letsencrypt/renewal/example.net.conf
Automatisation/usr/local/etc/periodic/weekly/500.certbot-3.11
Configuration periodic/etc/periodic.conf
Historique/var/log/letsencrypt/letsencrypt.log
Test manuelcertbot renew --dry-run

Commandes utilisées

 
Dernière édition:
  • J'adore
Réactions: EVO