Développeurs → Guides

Certificats wildcard avec DNS-01 et certbot

Le challenge DNS-01 prouve que vous contrôlez un domaine grâce à un enregistrement TXT plutôt qu'à une page web. C'est le seul moyen d'obtenir un certificat wildcard, et il fonctionne pour les serveurs inaccessibles depuis Internet. Ce hook permet à certbot de publier cet enregistrement via l'API NameOcean.

NameOcean émet lui-même un certificat wildcard gratuit pour tout domaine sur NameOcean DNS, le renouvelle et vous fournit un lien de téléchargement (SSL, ou POST /ssl/example.com). Utilisez ce guide lorsque votre serveur doit obtenir et renouveler son propre certificat.

Prérequis

  • Le DNS du domaine chez NameOcean (serveurs de noms ns1.nameocean.net à ns4.nameocean.net).
  • certbot, dig (dnsutils ou bind-utils) et la CLI nameocean sur le serveur.
  • Une clé API avec dns:read et dns:write. Limitez-la si possible à l'adresse IP du serveur.

1. Installer le hook

root@server
# curl -fsSL https://nameocean.net/install.sh | sh
# curl -fsSL https://nameocean.net/developers/guides/letsencrypt-dns-01/nameocean-hook.sh \
    -o /etc/letsencrypt/nameocean-hook.sh
# chmod 700 /etc/letsencrypt/nameocean-hook.sh
# echo 'NAMEOCEAN_API_KEY=no_live_…' > /etc/letsencrypt/nameocean.env
# chmod 600 /etc/letsencrypt/nameocean.env

La clé reste dans un fichier lisible uniquement par root ; les paramètres de renouvellement enregistrés par certbot ne la contiennent jamais.

2. Obtenir le certificat

root@server
# certbot certonly --manual --preferred-challenges dns \
    --manual-auth-hook "/etc/letsencrypt/nameocean-hook.sh auth" \
    --manual-cleanup-hook "/etc/letsencrypt/nameocean-hook.sh cleanup" \
    -d example.com -d "*.example.com"

Pour chaque nom, le hook trouve la zone correspondante parmi vos zones NameOcean, ajoute _acme-challenge comme enregistrement TXT et attend que les quatre serveurs de noms le renvoient, généralement en moins de dix secondes. Après la vérification, l'étape de nettoyage supprime exactement l'enregistrement ajouté. example.com et *.example.com utilisent tous deux _acme-challenge.example.com ; les deux valeurs sont publiées côte à côte.

3. Renouvellements

certbot enregistre les hooks avec le certificat, son timer le renouvelle donc de la même manière. Testez-le une fois :

root@server
# certbot renew --dry-run

Chaque enregistrement ajouté ou supprimé par le hook apparaît dans Tableau de bord → Activité avec la clé utilisée, et déclenche les événements webhook dns.record.created et dns.record.deleted.

Le hook

Lisez-le avant de l'exécuter en tant que root. Il appelle uniquement la CLI nameocean et dig.

/etc/letsencrypt/nameocean-hook.sh
#!/bin/sh
# certbot DNS-01 hooks for NameOcean DNS:
#   --manual-auth-hook "/etc/letsencrypt/nameocean-hook.sh auth"
#   --manual-cleanup-hook "/etc/letsencrypt/nameocean-hook.sh cleanup"
# Needs the nameocean CLI and an API key with dns:write, in /etc/letsencrypt/nameocean.env:
#   NAMEOCEAN_API_KEY=no_live_...
set -e
[ -f /etc/letsencrypt/nameocean.env ] && . /etc/letsencrypt/nameocean.env && export NAMEOCEAN_API_KEY

# the zone CERTBOT_DOMAIN is in: the longest of your zones it ends with
zone="$NAMEOCEAN_ZONE"
if [ -z "$zone" ]; then
  for z in $(nameocean dns ls --json | sed -n 's/.*"name": *"\([^"]*\)".*/\1/p'); do
    case "$CERTBOT_DOMAIN" in "$z" | *".$z") [ ${#z} -gt ${#zone} ] && zone="$z" ;; esac
  done
fi
[ -n "$zone" ] || { echo "no NameOcean DNS zone for $CERTBOT_DOMAIN" >&2; exit 1; }
name="_acme-challenge"
[ "$CERTBOT_DOMAIN" = "$zone" ] || name="_acme-challenge.${CERTBOT_DOMAIN%.$zone}"

case "$1" in
auth)
  id=$(nameocean dns add "$zone" TXT "$name" "$CERTBOT_VALIDATION" --ttl 5m --json \
    | sed -n 's/.*"id": *\([0-9][0-9]*\).*/\1/p' | head -n 1)
  [ -n "$id" ] || { echo "could not add the TXT record" >&2; exit 1; }
  echo "$id" # certbot passes this to the cleanup hook as CERTBOT_AUTH_OUTPUT
  # wait until all four nameservers answer with it (usually a few seconds)
  for i in $(seq 1 60); do
    n=0
    for ns in ns1 ns2 ns3 ns4; do
      dig +short TXT "$name.$zone" "@$ns.nameocean.net" | grep -q -- "$CERTBOT_VALIDATION" && n=$((n + 1))
    done
    [ "$n" -eq 4 ] && exit 0
    sleep 2
  done
  echo "the TXT record is not on every nameserver after 2 minutes" >&2
  exit 1
  ;;
cleanup)
  [ -z "$CERTBOT_AUTH_OUTPUT" ] || nameocean dns rm "$zone" TXT "$CERTBOT_AUTH_OUTPUT"
  ;;
*)
  echo "usage: $0 auth|cleanup" >&2
  exit 2
  ;;
esac

Sans la CLI

Le hook effectue deux appels API que vous pouvez reproduire depuis n'importe quel client ACME ou langage :

curl
$ curl -X POST https://nameocean.net/api/v1/dns/example.com/records \
    -H "Authorization: Bearer $NAMEOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d '{"type": "TXT", "hostname": "_acme-challenge", "text": "<validation>", "ttl": "5m"}'
{"id": 4190, "type": "TXT", "hostname": "_acme-challenge", …}
$ curl -X DELETE https://nameocean.net/api/v1/dns/example.com/records/TXT/4190 \
    -H "Authorization: Bearer $NAMEOCEAN_API_KEY"