Certbot und DuckDNS

Der Certbot kann die Eingerichten Domänen auch automatisch aktualisieren. Dazu ist für ausgefallene Anwendungszwecke ein Hooksystem integriert, sodass das Aktualisieren der Zertifikate auch unter besonderen Umständen funktioniert.

Wie der Titelschon beschreibt, will ich hier die Automatisation der Erneuerung der Zertifikate mit dem Certbot auf einer DuckDNS Domäne demonstrieren. In diesem Artikel habe ich die Einrichtung von DuckDNS bereits erleutert. Als Zeitgeber setze ich den Systemd Timer ein.

Manuelles ReNew

Die Zertifikate die LetsEncrypt ausstellt haben immer nur einen Gültigskeitszeitraum von genau 3 Monaten. Das heißt alle 3 Monate muss das Zertifikat erneuert und in den WebServer deployt werden, da sonst weiterhin die Aĺten abgelaufenen Zertifikate ausgeliefert werden und somit die Seiten von den Browsern als nicht vertrauenswürdig eingestuft werden.

Für DuckDNS bietet sich die Verifikationsmethode DNS01 an. Bei dieser Methode wird ein TXT Record im DNS Server erwartet. Dieses sogenannte Challenge muss vor der Überprüfung gesetzt werden. Hierfür wird das PRE Hook verwendet, um das Secret in DuckDNS zu setzen.

Die Informationen zu den Hooks kann man hier nachlesen.

Die Skripte die in den Hooks eingesetzt werden in einem Unterverzeichnis /duckdns im Ordner /etc/letsencrypt abgelegt.

Der PRE Hook

Dieses Skript wird in der Vorbereitung der Verifikation der Domäne ausgeführt. Es muss beim dem DNS01 Verfahren, also zum setzen der Challenge im DNS Server, genutzt werden. Dieses Skript hängen wir in den PRE Hook mit dem Parameter –manual-auth-hook ein. Dieser erwartet Pfad zu dem folgenden Skript…

Die Datei set_acme_challenge.sh in /etc/letsencrypt/duckdns/

#!/bin/bash

token="TTTTTTTT-TTTT-TTTT-TTTT-TTTTTTTTTTTT"

# log
echo "renewal of $CERTBOT_DOMAIN with challenge $CERTBOT_VALIDATION" 

# set acme challenge
curl -s "https://www.duckdns.org/update?domains=$CERTBOT_DOMAIN&token=$token&txt=$CERTBOT_VALIDATION"

Im Log werden in den meisten Fällen aufgeführt werden, dass das Aktualisieren nicht durchgeführt worden ist, weil das Zertifikat noch länger als 30 Tage gültig ist. Erst wenn die Gültigkeitsdauer klein 30 Tage ist, dann wird der Certbot eine Aktualisierung durchführen.

DNS Server Aufräumen

Nachdem das Challenge verifiziert worden ist, wird das Challenge auf dem DNS Server von DuckDNS nicht mehr benötigt. Das heißt es kann wieder gelöscht werden. Dazu verwenden wird den Hook –manual-cleanup-hook Parameter.

Die Datei clanup_acme_challenge.sh in /etc/letsencrypt/duckdns/

#!/bin/bash

# DuckDNS Token
token="TTTTTTTT-TTTT-TTTT-TTTT-TTTTTTTTTTTT" 

# clear acme challenge
curl -s "https://www.duckdns.org/update?domains=$CERTBOT_DOMAIN&token=$token&txt=$CERTBOT_VALIDATION&clear=true

Das aktuelle Zertifikat dem WebServer bekannt machen

Nachdem nun der Certbot das aktuelle Zertifikat bereitgestellt hat, dann muss das dem WebServer bekannt gemacht werden. Da ich den NginX WebServer einsetze, muss ich also ein systemctl reload nginx.service ausführen. Dies übergeben wir einfach direkt dem Deploy-Hook mit

--deploy-hook "systemctl reload nginx.service"

Der komplette Aufruf

Wenn wir jetzt alles zusammenführen, dann ergibt sich folgender Aufruf:

certbot renew --manual-auth-hook=/etc/letsencrypt/duckdns/set_acme_challenge.sh --manual-cleanup-hook=/etc/letsencrypt/duckdns/clear_acme_challenge.sh --deploy-hook "systemctl reload nginx.service"

Für Debuggingzwecke empfiehlt es sich sich noch den DRY RUN Modus mit dem Parameter –dry-run zu aktivieren.

Den Systemd Timer anlegen

Der certbot.service:

[Unit]
Description=Let's Encrypt renewal

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --manual-auth-hook=/etc/letsencrypt/duckdns/set_acme_challenge.sh --manual-cleanup-hook=/etc/letsencrypt/duckdns/clear_acme_challenge.sh --deploy-hook "systemctl reload nginx.service"

Der certbot.timer:

[Unit]
Description=Twice daily renewal of Let's Encrypt's certificates

[Timer]
OnCalendar=0/12:00:00
RandomizedDelaySec=1h
Persistent=true

[Install]
WantedBy=timers.target

Log

Das Log kann mit journalctl -n50 -fu certbot.service eingesehen werden:

Nov 24 14:14:04 server systemd[1]: Starting Let's Encrypt renewal...
Nov 24 14:14:07 server certbot[2160]: Saving debug log to /var/log/letsencrypt/letsencrypt.log
Nov 24 14:14:07 server certbot[2160]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nov 24 14:14:07 server certbot[2160]: Processing /etc/letsencrypt/renewal/XXXX.duckdns.org.conf
Nov 24 14:14:07 server certbot[2160]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nov 24 14:14:08 server certbot[2160]: Cert not yet due for renewal
Nov 24 14:14:08 server certbot[2160]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nov 24 14:14:08 server certbot[2160]: The following certs are not due for renewal yet:
Nov 24 14:14:08 server certbot[2160]:   /etc/letsencrypt/live/XXXX.duckdns.org/fullchain.pem expires on 2020-02-21 (skipped)
Nov 24 14:14:08 server certbot[2160]: No renewals were attempted.
Nov 24 14:14:08 server certbot[2160]: No hooks were run.
Nov 24 14:14:08 server certbot[2160]: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nov 24 14:14:08 server systemd[1]: certbot.service: Succeeded.
Nov 24 14:14:08 server systemd[1]: Started Let's Encrypt renewal.

Wildcard Zertifikat

Der freie DNS Dienst DuckDNS bietet Unterstützung für TXT records an. Zudem werden beliebige SubDomains unterstützt, sodass das zusammen für die Validierung von Wildcard Zertifikaten von Let’s Encrypt zu gebrauchen ist. Mit den Wildcard Zertifikat kann man lokale Dienste auch über SSL verschlüsseln. Dazu kann man den NginX oder den Apache WebServer als Reverse Proxy einrichten.

Einrichtung mit Certbot

Unter Arch Linux verwende ich Certbot, um den Request anzufordern und die Challange zu lösen. Das lösen der Challange und somit die Validierung der Domain, geschiet in dem man ein Secret (Key) als TXT record Let’s Encrypt auf der Domain bereit stellt.

1. Schritt – Anforderung eines Wildcard Zertifikat

Als erstes müssen wir mit dem Certbot ein Wildcard Zertifikat anfordern. Das macht der Parameter -d. Tragen Sie hier ihre DuckDNS Domain ein für die sie ein Wildcard Zertifikat beantragen möchten. In diesem Beispiel also *.XXXXXXXXX.duckdns.org.

#request wildcard certificate
certbot --server https://acme-v02.api.letsencrypt.org/directory -d *.XXXXXXXXX.duckdns.org --manual --preferred-challenges dns-01 certonly

Beantworten Sie die Frage nach dem IP-Logging mit y.

certbot --server https://acme-v02.api.letsencrypt.org/directory -d *.XXXXXXXXX.duckdns.org --manual --preferred-challenges dns-01 certonly
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 XXXXXXXXX.duckdns.org

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.XXXXXXXXX.duckdns.org with the following value:

JAn7QDG3W4f-RqbztXnwkjET3DpU7GTImcysQfH60zE

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

Wichtig: Es muss nun zunächst der TXT record bei DuckDNS angelegt werden. Wechseln Sie zunächst in ein neues Terminal, bevor sie fortfahren.

2. Das Secret bereitstellen

Die Validierung, ob sie wirklich der Inhaber (oder berechtigter) sind, geschiet über ein Sekret welches sie in einem TXT record hinterlegen müssen. Wie sie der Ausgabe oben entnehmen können, ist das in diesem Fall der Key JAn7QDG3W4f-RqbztXnwkjET3DpU7GTImcysQfH60zE.

Die API von DuckDNS erlaubt es das setzen und löschen TXT records. Durch einen einfachen Aufruf mit curl sind wir in der Lage das Sekret zu setze.

 curl "https://www.duckdns.org/update?domains=XXXXXXXXX.duckdns.org&token=TTTTTTTT-TTTT-TTTT-TTTT-TTTTTTTTTTTT&txt=JAn7QDG3W4f-RqbztXnwkjET3DpU7GTImcysQfH60zE"

3. Überprüfen ob der TXT record gesetzt ist

In der UI von DuckDNS kann man leider die TXT records nicht erkennen. Daher können sie zum beispiel mit dig oder einem Online Dig Dienst dieses prüfen.

Ich nutze hier, wie von DuckDNS vorgeschlagen www.digwebinterface.com.

 https://www.digwebinterface.com/?hostnames=XXXXXXXXX.duckdns.org&type=TXT&ns=resolver&useresolver=8.8.4.4&nameservers=

Überprüfen sie mit dig, ob der TXT record verfügbar ist. Solange er nicht gesetzt ist, können sie mit dem nächsten Schritt nicht weiter machen.

4. Certbot Validierung fortsetzen

Nun kann die Validierung fortgesetzt werden und somit die Erstellung abgeschlossen werden.

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/XXXXXXXXX.duckdns.org/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/XXXXXXXXX.duckdns.org/privkey.pem
   Your cert will expire on 2019-08-25. 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

Nun stehen die Dateien unter /etc/letsencrypt/live/XXXXXXXXX.duckdns.org/ bereit.

5. Cleanup – TXT record löschen

Die API von DuckDNS erlaubt, wie oben beschrieben, auch das löschen von TXT records. Der Aufruf ist identisch, bis auf das zusätzlich der Parameter clear=true mit angehangen wird.

curl "https://www.duckdns.org/update?domains=XXXXXXXXX.duckdns.org&token=TTTTTTTT-TTTT-TTTT-TTTT-TTTTTTTTTTTT&txt=JAn7QDG3W4f-RqbztXnwkjET3DpU7GTImcysQfH60zE&clear=true"

Szenrio

Gegeben sei eine Domain die bei dem DynDNS Provider duckdns.org gehostet wird. Es sind aber als Einschränkung bei DuckDNS nur maximal 5 SubDomains erlaubt.

Eine Lösung – Pfade verwenden

Eine Lösung kann sein, dass man eine SubDomain verwendet, um über die Pfade den Dienst mit Hilfe des Reverse Proxys aufzulösen.

Hier nun der Server Abschnitt um einen Dienst der in dem lokalen Netz auf der IP Addresse 192.168.2.2 Port 4711 lauscht. Diesen werden wir auf der Domain xxx.duckdns.org/service bekannt machen.

server {
    listen 80;
    server_name xxx.duckdns.org;

    #
    # Serve service on path http://xxx.duckdns.org/service and map it to 192.168.2.2:4711
    #
    location /service/ 
    {
        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;

        proxy_pass              http://192.168.2.2:4711/;

        proxy_read_timeout      600s;
        proxy_send_timeout      600s;
    }
}

Die proxy_pass Anweisung ist hier der wichtige Teil. Hiermit bestimmt man wo der Dienst erreichbar ist.

Duck DNS (www.duckdns.org) bietet eine einfache, schnelle und vor allem eine kostenlose Möglichkeit ein DNS Eintrag zu erhalten. Eine Registration ist nicht nötig, wenn man z.B. über einen Google Account (OAuth2) verfügt. Hier genügt es sich mit dem Button anzumelden.

Unter dem Link “install” finden sich für die gängigsten Router, Betriebssystem und weitere Programme Installationsanleitungen.

Beispiel Fritzbox mit 2 SubDomains

  • Anmeldung an der Fritzbox
  • Internet –> Freigaben –> Dynanic DNS
  • Benutzerdefiniert
  • Benutzername ist die Emailadresse mit der man sich registriert hat
  • Domainname eine der SubDomains eintragen
  • Update URL –> https://www.duckdns.org/update?domains=SubDomain1,SubDomain2&token=XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&ip=<ipaddr>&ipv6=<ip6addr>

Es muss nur die SubDomain angegeben werden. Mehrere Domains können per Komma getrennt gelistet werden. Den Update-Link inklusive Token aus der Installastionsanleitung kopieren und die Domains anpassen. ipaddr und ipv6addr sind Platzhalter in der Fritzbox und müssen genauso übergeben werden.