Priorisierung: 100-Dollar-Methode und Skala
9. März 2021Priorisierung mit dem Kano Modell
6. April 2021Let’s Encrypt Wildcard Zertifikate mit Ionos DNS API erzeugen
English version can be found on medium!
At the end of the day, the goals are simple: safety and security.
Jodi Rell
Der Großteil der Seitenaufrufe im Internet läuft mittlerweile über verschlüsselte Verbindungen. Damit zwischen Besuchern und der Website eine verschlüsselte Verbindung aufgebaut werden kann, muss diese ein Zertifikat bereitstellen, welches von einer vertrauenswürdigen Zertifizierungsstelle ausgestellt wurde.
Bis vor ein paar Jahren konnten solche Zertifikate meist ausschließlich bei kommerziellen Unternehmen (z.B. GeoTrust, DigiCert, usw.) beantragt werden. Diese verlangen für die Ausstellung der Zertifikate für gewöhnlich eine jährliche Gebühr. Mit Let’s Encrypt ist seit Ende 2015 eine Open-Source Zertifizierungsstelle verfügbar, welche kostenlose Zertifikate über ein automatisierteres Protokoll bereitstellt.
Um den Aufwand für die Verwaltung von vielen Subdomains und deren zugehöriger Zertifikate zu vermeiden, gibt es die Möglichkeit sogenannte Wildcard-Zertifikate zu nutzen. Die Beantragung solcher ist aber mitunter etwas komplizierter und war bisher bei dem DNS Provider Ionos in Verbindung mit Let’s Encrypt nur durch manuelle Interaktion möglich.
Was sind Wildcard Zertifikate?
Damit das eigene Zertifikat im Browser als „sicher“ angezeigt wird, muss dieses zuvor bei einer vertrauenswürdigen Zertifizierungsstelle (sogenannter CAs / Certificate Authorities) beantragt werden. Der Antrag für eine Domain kann dabei immer nur vom Besitzer gestellt werden. Wenn das Zertifikat nun für eine Website dem Browser vorgelegt wird, wird dieses anhand einer im Betriebssystem hinterlegten Liste von CAs geprüft.
Jedes Zertifikat hat einen eindeutigen Namen (der sogenannte „CN – Common Name“), welcher die Domain darstellt, die durch das Zertifikat geschützt werden soll. Wenn z.B. eine Website unter example.com aufgerufen wird, muss der Common Name des zugehörigen Zertifikats CN=example.com
heißen. Wenn nun eine Website unter sub.example.com bereitgestellt wird, braucht diese ihr eigenes Zertifikat mit dem Common Namen CN=sub.example.com
. Die Website unter der Subdomain kann nicht durch das Zertifikat der Top-Level-Domain (TLD) geschützt werden.
Sollte ein Unternehmen viele Subdomains verwenden, kann dies durchaus zu einem nicht zu unterschätzenden Verwaltungsaufwand werden, all die Zertifikate der einzelnen Subdomains zu pflegen. Aus diesem Grund gibt es die sogenannten Wildcard Zertifikate. Der Name impliziert bereits die Funktionalität dieses speziellen Typs.
Wenn der CN z.B. den Wert CN=*.example.com
enthält, werden automatisch die TLD und alle direkten Subdomains der TLD durch dieses Zertifikat geschützt. Das Zertifikat z.B. von google.de nutzte zeitweise genau diesen Mechanismus (CN=*.google.de
) (Stand: Anfang Februar 2021). Mittlerweile wird von Google wieder ein explizites Zertifikat für die Domain www.google.de verwendet.
Was ist Let’s Encrypt?
Es gibt schon sehr lange etablierte Zertifizierungsstellen, wie z.B. DigiCert, GeoTrust oder ähnliche. Da diese gewinnorientierte Unternehmen sind, verlangen diese für die „Beglaubigung“ der Zertifikate meist eine jährliche Gebühr. Seit Ende 2015 gibt es im Kontrast dazu eine Open-Source Zertifizierungsstelle namens Let’s Encrypt.
Let’s Encrypt ist eine freie, automatisierte und offene Zertifizierungsstelle, welche durch die Internet Security Research Group (ISRG) bereitgestellt wird. Let’s Encrypt nutzt zur Validierung des Eigentums einer Domain das Automated Certificate Management Environment (ACME) Protokoll, welches im RFC 8555 standardisiert wurde. Seit März 2018 bietet Let’s Encrypt mittels des ACMEv2 Protokolls auch Wildcard Zertifikate an (siehe auch Let’s Encrypt Blog Post).
Wie beantragt man (Wildcard) Zertifikate bei Let’s Encrypt?
Let’s Encrypt Zertifikate für eine konkrete Domain können durch die HTTP Challenge oder die DNS Challenge beantragt werden. Für Wildcard Zertifikat von Let’s Encrypt kann ausschließlich die DNS Challenge verwendet werden (siehe dazu den Beitrag in den Let’s Encrypt FAQ).
Bei der DNS Challenge wird die Validierung durch das Setzen von dedizierten DNS Einträgen bewerkstelligt. Das heißt, dass während des Prozesses ein TXT Eintrag z.B. für die Domain _acme-challenge.example.com
mit einem von Let’s Encrypt vorher definierten Wert erzeugt werden muss. Let’s Encrypt prüft dann, ob der vorgegebene Wert über das DNS System unter der genannten Domain abgerufen werden kann. Wenn ja, ist sichergestellt, dass die beantragende Person Zugriff auf die Domain hat und dementsprechend berechtigt ist, den Prozess durchzuführen.
Bisheriger Workflow von Let’s Encrypt mit Ionos DNS
Ionos als Domain und zugleich DNS Provider bot in der Vergangenheit lediglich die Möglichkeit DNS Einträge via Web-UI zu erstellen, zu ändern oder zu löschen. Da für den Validierungsprozess TXT Einträge im DNS für die Domain zur Verfügung stehen müssen, war es bisher nötig diese manuell hinzuzufügen und danach wieder zu entfernen.
Die Let’s Encrypt Zertifikate sind lediglich 3 Monate gültig. Deshalb muss dieser Vorgang regelmäßig und manuell durchgeführt werden. Die folgenden Schritte beschreiben in Kürze wie die Schritte bisher aussahen.
- Damit DNS Einträge erstellt bzw. gelöscht werden können, muss eine Authentifizierung an der Web-UI und eine Navigation zur DNS Verwaltung erfolgen.
- Der Validierungsprozess wird z.B. mit dem Certbot gestartet, indem man den folgenden Befehl ausführt (
<your.domain>
ersetzen mit der gewünschten TLD)
certbot certonly
-d *.<your.domain>
--preferred-challenges dns
--manual
- Während des DNS Challenge Protokolls wird der Prozess kurzzeitig pausiert, damit ein TXT Eintrag mit einem von Let’s Encrypt definierten Wert (
<acme-challenge-value>
) im DNS unter einer definierten Sub-Domain (_acme-challenge.<your.domain>
) eingetragen werden kann.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for <your.domain>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.<your.domain> with the following value:
<acme-challenge-value>
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
- Die Werte werden in der Ionos Web-UI eingetragen und gespeichert
- Nachdem die DNS Einträge gespeichert wurden, kann der Prozess fortgesetzt werden. Das Zertifikat wird nach erfolgreicher Prüfung der DNS Einträge erstellt und im Filesystem abgelegt.
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/<your.domain>/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/<your.domain>/privkey.pem
Your cert will expire on 2019-08-01.
To obtain a new or tweaked version of this certificate in the future,
simply run certbot again.
To non-interactively renew *all* of your certificates, run "certbot
renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: <https://letsencrypt.org/donate>
Donating to EFF: <https://eff.org/donate-le>
- Nach der DNS Challenge sollten die erstellten DNS Einträge wieder gelöscht werden. Das Löschen der Einträge wurde manuell in der Ionos Web UI durchgeführt.
Die neue Ionos DNS API
Seit Dezember 2020 stellt Ionos eine Beta API für ihr DNS System zur Verfügung. Im Developer Portal von Ionos gibt es eine Sektion für die DNS API mit einer Swagger UI. Für einen einfacheren Start wird ein “Getting Started” bereitgestellt, welches einige Details zur Nutzung und Registrierung zur Verfügung stellt. Damit die DNS API genutzt werden kann, muss eine Registrierung durchgeführt werden. Auf der Seite für den Abruf der zugehörigen API-Keys wird man dafür auf die Kontakt-Seite von Ionos verwiesen.
Info: Unserer eigenen Erfahrung nach kann die Registrierung nur über die Telefon-Support-Hotline erfolgen, da die Aktivierung der API eine kostenlose “Bestellung” des Zugriffs darstellt!
Nach erfolgreicher Bestellung kann im Developer Portal der “Zugriffsschlüssel” über den Button “Erstellen Sie einen neuen Schlüssel“ angefordert werden. Dieser besteht aus einem publicprefix
und einem secret
. Das secret
wird nur einmal angezeigt und sollte sicher abgespeichert werden.
Automatisierungsskripte
Für die Automatisierung des Prozesses zur Validierung gibt es für vereinzelte DNS Provider ein Plugin für das Tool Certbot, welche über die APIs der jeweiligen Provider die Einträge anlegen bzw. entfernen. Für Ionos gibt es kein solches Plugin. Es gibt aber alternativ die Möglichkeit den Prozess mit Shell-Skripten für Certbot selbst zu automatisieren.
Im Folgenden stellen wir solche Shell-Skripte vor, welche verwendet werden können, um Wildcard-Zertifikate mit dem DNS Provider Ionos automatisiert zu erstellen. Danach stellen wir vor, wie die Skripte in Verbindung mit Certbot genutzt werden können.
Auth Hook
Das Auth Hook Script erstellt die für die Validierung der Domain nötigen DNS Einträge bei Ionos über die DNS API. Dabei werden von dem Certbot Tool zur Laufzeit gewisse Environment Variablen gesetzt, die während der Verarbeitung verwendet werden können. Dazu gehören z.B. die zu validierende Domain (CERTBOT_DOMAIN
) oder das token für die Validierung der Domain (CERTBOT_VALIDATION
).
Vorbedingung: Auf dem System, welches das Script ausführt, muss curl
& python
installiert sein!
Ausführungshinweis: Um Debug-Logs angezeigt zu bekommen, kann das #
Zeichen vor dem Command set -x
entfernt werden.
Auth Hook Shell Script
Im ersten Schritt sucht das Script den Namen der DNS Zone anhand der Domain, für die ein Zertifikat beantragt wird. Im nächsten Schritt wird über die DNS API der Identifier für die Zone bei Ionos abgefragt. Dieser Identifier wird benötigt, um über die API DNS Einträge in dieser Zone anzulegen. Folgend wird der TXT DNS Eintrag mit dem Validierungstoken unter der vom Let’s Encrypt erwarteten Subdomain (_acme-challenge.<your.domain>
) erstellt. Schlussendlich wird noch der Identifier der Zone in eine temporäre Datei geschrieben, welche später für das Cleanup verwendet wird.
#!/bin/sh
#set -x
API_URL="https://api.hosting.ionos.com/dns/v1"
API_KEY_HEADER="X-API-Key: $API_KEY"
# Strip only the top domain to get the zone id
ZONE_NAME=$(expr match "$CERTBOT_DOMAIN" '.*\.\(.*\..*\)')
# When already the TLD then use it
if [ -z "$ZONE_NAME" ]; then
ZONE_NAME="$CERTBOT_DOMAIN"
fi
# Get the Ionos zone id
ZONE_RESPONSE=$(curl -s -X GET "$API_URL/zones" \
-H "$API_KEY_HEADER" \
-H "Accept: application/json")
ZONE_ID=$(echo $ZONE_RESPONSE \
| python -c "import sys,json;response=json.load(sys.stdin);print(next((x for x in response if x['name']=='$ZONE_NAME'))['id'])")
# Create TXT record
CREATE_DOMAIN="_acme-challenge.$CERTBOT_DOMAIN"
RECORD_CREATE_RESPONSE=$(curl -s -X POST "$API_URL/zones/$ZONE_ID/records" \
-H "$API_KEY_HEADER" \
-H "Content-Type: application/json" \
--data '[{"name": "'"$CREATE_DOMAIN"'", "type": "TXT", "content": "'"$CERTBOT_VALIDATION"'", "ttl": 3600, "prio": 100, "disabled": false}]')
# Save info for cleanup
echo $ZONE_ID > /tmp/CERTBOT_$CERTBOT_DOMAIN
# Sleep to make sure the change has time to propagate over to DNS
sleep 25
Cleanup Hook
Das Cleanup Hook Script löscht die für die Validierung der Domain erstellten DNS Einträge bei Ionos über die DNS API.
Vorbedingung: Auf dem System, welches das Script ausführt, muss curl
& python
installiert sein!
Ausführungshinweis: Um Debug-Logs angezeigt zu bekommen, kann das #
Zeichen vor dem Command set -x
entfernt werden.
Cleanup Hook Shell Script
Im ersten Schritt prüft das Script, ob für die validierte Domain eine Datei existiert, welche einen Identifier einer DNS Zone enthält. Existiert diese, werden für diese Zone über die DNS API alle Identifier derjenigen DNS Einträge abgerufen, die für die Validierung der Domain erstellt wurden. Schlussendlich werden alle gefunden DNS Einträge anhand ihrer Identifier über die DNS API gelöscht.
#!/bin/sh
#set -x
API_URL="https://api.hosting.ionos.com/dns/v1"
API_KEY_HEADER="X-API-Key: $API_KEY"
if [ -f /tmp/CERTBOT_$CERTBOT_DOMAIN ]; then
ZONE_ID=$(cat /tmp/CERTBOT_$CERTBOT_DOMAIN)
rm -f /tmp/CERTBOT_$CERTBOT_DOMAIN
CREATE_DOMAIN="_acme-challenge.$CERTBOT_DOMAIN"
# request the created records
RECORD_GET_RESPONSE=$(curl -s -X GET "$API_URL/zones/$ZONE_ID?recordName=$CREATE_DOMAIN&recordType=TXT" \
-H "$API_KEY_HEADER" \
-H "Accept: application/json")
RECORD_IDS=$(echo $RECORD_GET_RESPONSE \
| python -c "import sys,json;records=json.load(sys.stdin)['records'];print('\n'.join([x['id'] for x in records]))")
fi
# Remove the challenge TXT record from the zone
if [ -n "$ZONE_ID" -a -n "$RECORD_IDS" ]; then
echo "$RECORD_IDS" \
| xargs -n1 -I {} curl -s -X DELETE "$API_URL/zones/$ZONE_ID/records/{}" \
-H "$API_KEY_HEADER"
fi
Verwendung
Der Einfachheit halber nutzen wir für die Demo das offizielle Certbot Docker Image. Dort ist bereits das Tool certbot
und python
installiert. Damit das Zertifikat erstellt werden kann, müssen verschiedene Dinge vorbereitet werden.
- Ein Ordner für die Let’s Encrypt Zertifikat Struktur muss erstellt werden. In unserem Beispiel liegt dieser unter
/opt/letsencrypt/cert
- Ein Ordner, in dem die Skripte abliegen. In unserem Beispiel liegen diese unter
/opt/letsencrypt/scripts
und sind ausführbar (chmod +x /opt/letsencrypt/scripts/*.sh
)/opt/letsencrypt/scripts/authenticate.sh
/opt/letsencrypt/scripts/cleanup.sh
- Einerseits muss der API Zugriff beantragt worden sein (siehe oben) und andererseits muss der
<publicprefix>
und das<secret>
im folgenden Codeblock entsprechend ersetzt werden.- HINWEIS: Es muss ein Punkt (
.
) zwischenpublicprefix
undsecret
gesetzt werden!
- HINWEIS: Es muss ein Punkt (
- Eine Email für Expiration Benachrichtigungen und als Identifier für einen Let’s Encrypt Account muss im folgenden Codeblock (
<email-address>
) entsprechend ersetzt werden - Die Domain, für die das Zertifikat erstellt werden soll, muss im folgenden Codeblock ersetzt werden (
<your.domain>
)
Ausführungshinweis: Da das Certbot Docker Image das Tool curl
nicht installiert hat, muss dies zusätzlich hinzugefügt werden. Am einfachsten wird dies bewerkstelligt, indem man im Auth Hook Script den Befehl apk add curl
z.B. in der Zeile 3 einfügt. Alternativ könnte ein eigenes Docker Image erstellt werden, welches im zugehörigen Dockerfile das Tool curl
installiert.
docker run -i --rm \
-v /opt/letsencrypt/cert:/etc/letsencrypt \
-v /opt/letsencrypt/scripts:/tmp/scripts \
-e "API_KEY=<publicprefix>.<secret>" \
certbot/certbot \
certonly \
--keep-until-expiring \
--preferred-challenges dns \
--non-interactive \
--agree-tos \
-m <email-address> \
--manual \
--manual-auth-hook /tmp/scripts/authenticate.sh \
--manual-cleanup-hook /tmp/scripts/cleanup.sh \
-d *.<your.domain>
Nach erfolgreicher Validierung liegt das Zertifikat, die vollständige Zertifikats-Kette und der zugehörige Private Key in dem Verzeichnis /opt/letsencrypt/cert/live/<your.domain>
.
Zusammenfassung
Mithilfe der zwei Shell Skripte kann der Prozess zur Beantragung und dem Erneuern von Wildcard-Zertifikaten komplett automatisiert werden. Der oben gezeigte Befehl kann z.B. mittels eines Cronjobs auf einem Server regelmäßig ausgeführt werden. Damit wird verhindert, dass das Zertifikat ausläuft und die Besucher der Website eine Fehlermeldung/Warnhinweis angezeigt bekommen. Perspektivisch wäre die Implementierung eines nativen Plugins für das Tool Certbot wünschenswert, aber bis dahin, können die gezeigten Skripte verwendet werden 🙂