Προγραμματιστές → Οδηγοί

Πιστοποιητικά wildcard με DNS-01 και certbot

Η πρόκληση DNS-01 αποδεικνύει ότι ελέγχετε ένα domain μέσω μιας εγγραφής TXT αντί για μια ιστοσελίδα. Είναι ο μόνος τρόπος για να αποκτήσετε πιστοποιητικό wildcard και λειτουργεί για διακομιστές που δεν είναι προσβάσιμοι από το διαδίκτυο. Αυτό το hook επιτρέπει στο certbot να δημοσιεύει αυτή την εγγραφή μέσω του NameOcean API.

Το ίδιο το NameOcean εκδίδει δωρεάν πιστοποιητικό wildcard για κάθε domain στο NameOcean DNS, το ανανεώνει και σας δίνει σύνδεσμο λήψης (SSL ή POST /ssl/example.com). Χρησιμοποιήστε αυτόν τον οδηγό όταν ο διακομιστής σας πρέπει να αποκτά και να ανανεώνει το δικό του πιστοποιητικό.

Τι χρειάζεστε

  • Το DNS του domain στο NameOcean (nameservers ns1.nameocean.net έως ns4.nameocean.net).
  • Τα certbot, dig (dnsutils ή bind-utils) και το CLI nameocean στον διακομιστή.
  • Ένα κλειδί API με dns:read και dns:write. Περιορίστε το στη διεύθυνση IP του διακομιστή, αν είναι δυνατόν.

1. Εγκατάσταση του 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

Το κλειδί παραμένει σε ένα αρχείο που μπορεί να διαβάσει μόνο ο root· οι αποθηκευμένες ρυθμίσεις ανανέωσης του certbot δεν το περιέχουν ποτέ.

2. Απόκτηση του πιστοποιητικού

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"

Για κάθε όνομα, το hook βρίσκει τη ζώνη στην οποία ανήκει ανάμεσα στις ζώνες σας στο NameOcean, προσθέτει το _acme-challenge ως εγγραφή TXT και περιμένει μέχρι να απαντούν με αυτήν και οι τέσσερις nameservers, συνήθως μέσα σε δέκα δευτερόλεπτα. Μετά τον έλεγχο, το βήμα καθαρισμού διαγράφει ακριβώς την εγγραφή που πρόσθεσε. Τα example.com και *.example.com χρησιμοποιούν και τα δύο το _acme-challenge.example.com· οι δύο τιμές δημοσιεύονται η μία δίπλα στην άλλη.

3. Ανανεώσεις

Το certbot αποθηκεύει τα hooks μαζί με το πιστοποιητικό, οπότε ο χρονοδιακόπτης του το ανανεώνει με τον ίδιο τρόπο. Δοκιμάστε το μία φορά:

root@server
# certbot renew --dry-run

Κάθε εγγραφή που προσθέτει και διαγράφει το hook εμφανίζεται στο Dashboard → Δραστηριότητα μαζί με το κλειδί που το έκανε και στέλνει συμβάντα webhook dns.record.created και dns.record.deleted.

Το hook

Διαβάστε το πριν το εκτελέσετε ως root. Καλεί μόνο το CLI nameocean και το 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

Χωρίς το CLI

Το hook κάνει δύο κλήσεις API που μπορείτε να κάνετε από οποιονδήποτε πελάτη ACME ή γλώσσα:

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"