Let’s Encrypt: Wildcards mit PowerDNS

Seit einiger Zeit bietet die kostenlose & offene CA Let’s Encrypt auch Wildcard-Zertifikate an: Nun muss man nicht mehr für jede Subdomain eine einzelnes Zertifikat beantragen (wobei es hier ein Limit gibt), sondern kann mittels eines Wildcards (*.example.com) alle Subdomains abdecken, also a.example.com, b.example.com usw.

Zu beachten ist hierbei, das ein Wildcard nicht für die Domain selbst gilt, für example.com braucht man also weiterhin ein seperates Zertifikat. Um dies zu vereinfachen, kann man natürlich auch einfach beides als URL für ein Zertifikat verwenden.

Um nachzuweisen, das man wirklich berechtigt ist, Zertifikate für eine Domain zu bekommen, wird bei Wildcards die DNS-01 Challenge vorrausgesetzt:

Man bekommt von LE eine Art Code, und muss diesen im DNS der entsprechenden Domain veröffentlichen, genauer gesagt als TXT-Record unter _acme-challenge.<domain>.<tld>

Wenn man seine Zonen auf einem eigenen Server, z.B. mit PowerDNS hat, gestaltet sich das automatisierte einfügen relativ einfach. Ich verwende hierzu dehydrated von lukas2511, den Hook pdns_api.sh sowie die HTTP-API von PowerDNS. Hierbei kümmert sich Dehydrated um die Generierung und Signierung der Zertifikate, pdns_api.sh schiebt die Challenge über die PowerDNS-API in die entsprechende Zone und PowerDNS macht den Rest (ausliefern an Slaves etc.)

Benötigt wird natürlich PowerDNS (am besten in der aktuellen Version 4.1, siehe https://repo.powerdns.com/), sowie die Abhängigkeiten von Dehydrated (cURL, sed, grep, mktemp, openssl).

Fangen wir an mit der Konfiguration von PowerDNS:


webserver=yes
api=yes
api-key=hier_key_einsetzen
webserver-allow-from=0.0.0.0/0
webserver-address=0.0.0.0
default-soa-edit=INCEPTION-INCREMENT

Diese Zeilen müssen in eine Konfigurationsdatei von PDNS, z.B. /etc/powerdns/pdns.d/api.conf
Der Key sollte natürlich frei und möglichst sicher/lang gewählt werden.

Wenn der API-Aufruf nur vom Localhost erfolgt (=Dehydrated auf der selben Maschine wie PowerDNS), kann man die Einträge webserver-allow-from und webserver-address auch weglassen.

Nach einem Neustart von PowerDNS kümmern wir uns nun um dehydrated:

In einem geeigneten Verzeichnis (z.B. /etc, sodass alles unter /etc/dehydrated liegt) genügt ein git clone https://github.com/lukas2511/dehydrated, um dehydrated zu installieren.

Weiterhin holen wir uns die Datei pdns_api.sh ins selbe Verzeichnis (also /etc/dehydrated/pdns_api.sh), machen sie ausführbar (chmod +x /etc/dehydrated/pdns_api.sh) und konfigurieren dehydrated.

Die Haupteinstellungen findet man in der Datei /etc/dehydrated/config, diese kann am Ende z.B. so aussehen:

# Wir nutzen Verifizierung über DNS
CHALLENGETYPE="dns-01"
# pdns_api.sh soll aufgerufen werden
HOOK="/etc/dehydrated/pdns_api.sh"
# Es können mehrere Domains auf einmal validiert werden
HOOK_CHAIN="yes"
# Ab hier die Einstellungen für den Hook
PDNS_HOST=127.0.0.1 # Host von PowerDNS, 127.0.0.1 für die selbe Maschine
PDNS_PORT=8081 # Port ist normalerweise 8081
PDNS_KEY=hier_key_einsetzen # API key von PowerDNS
PDNS_VERSION=1 # API-Version, 1 für > PowerDNS 4, sonst 0
PDNS_WAIT=90 # Zeit, die gewartet werden soll, bis die Validierung/Challenge überprüft wird.
# In dieser Zeit müssen alle Slaves/anderen Server die Änderungen mitbekommen haben.

Außerdem müssen wir dehydrated noch mitteilen, für welche Domains er Zertifikate besorgen soll. Dazu öffnen wir die domains.txt in /etc/dehydrated, und tragen unsere Domains ein, wobei eine Zeile immer einem Zertifikat entspricht, z.B.:


marvingaube.de *.marvingaube.de


In diesem Beispiel wird ein Zertifikat für marvingaube.de mit dem alternativen Namen *.marvingaube.de (also dem Wildcard) besorgt, was dann im Zertifikat marvingaube.de landet.

Ist alles eingetragen, kann man dehydrated mit

/etc/dehydrated/dehydrated -c

durchlaufen lassen, und hoffen, das keine Fehlermeldungen kommen.

Ist alles ohne Fehler durchgelaufen, liegen die Zertifikate im Ordner /etc/dehydrated/certs/<Zertifikatsname>/, dort gibt es, wie man es von LE gewohnt ist, die privkey.pem, fullchain.pem, cert.pem und chain.pem.

Zum erneuern der Zertifikate einfach erneut dehydrated -c ausführen, dies lässt sich auch gut in einen Cronjob packen.

Probleme

Folgende Probleme sind bei mir aufgetreten:

Die Validierung schlägt fehl:

Hier muss man schauen, woran es liegt. Ich hatte mal den Fall, dass die Serial-Nummer im SOA-Record nicht erhöht wurde, daher haben die Slaves nichts von der Änderung in der Zone mitbekommen.

Hierfür muss man PowerDNS beibringen, die Serials automatisch zu erhöhen, oder notfalls per Hand eingreifen (was aber sehr unschön ist).

pdnsutil show-zone zone hilft, um sich die aktuelle Serial anzeigen zu lassen (und ob bereits ein notify an die Slaves stattgefunden hat). Oft hilft es auch, die Zeit in PDNS_WAIT höher zu setzen.

Es werden nicht mehrere TXT-Records für denselben Hostname unterstützt:

Wenn man ein Zertifikat für example.com und *.example.com gleichzeitig authentifiziert, gibt es zwei Records für _acme-challenge.example.com

Hierbei kann es passieren, das bestimmte Authoritative Nameserver dies nicht unterstützen. Die Lösung ist, HOOK_CHAIN="no" zu setzen. Nun wird die Validierung nacheinander ausgeführt.

Bei Problemen, Fragen oder Anregungen freue ich mich auch gerne über Kommentare 😉