SSL-Zertifikate mit Dehydrated

25.09.2020 - Jürgen Peters

Dieser Artikel beschreibt die Installation und Konfiguration der Software dehydrated zum Zwecke der regelmäßigen, automatisierten Beschaffung von signierten SSL Zertifikaten. Dabei werden lediglich die notwendigen Schritte zum regelmäßigen beziehen von Zertifikaten exemplarisch vorgestellt. Für weitergehende Informationen ist das Studium der Dokumentation der einzelnen Dienste zu empfehlen.

Das hier beschriebene System läuft unter FreeBSD. Web- und Mailserver sollen mit jeweils unterschiedlichen Zertifikaten versorgt werden. Die Dienste laufen jeweils in ihren eigenen Jails „www“ und „mail“. Diese Jails wurden mit iocage eingerichtet und verwaltet. In unserem konkreten Fall wird nginx als Web- und das Gespann aus Postfix und Dovecot als Mailserver verwendet. Als Certificate Authority (CA), von der wir unsere Zertifikate signieren lassen, wird Let’s Encrypt genutzt.

Dehydrated selbst ist allerdings sehr flexibel und lässt sich leicht für viele andere Szenarien als dem hier beschriebenen anpassen. Außerdem benötigt dehydrated lediglich eine Bash und curl sowie Zugang zu einem entsprechenden Web- oder DNS-Server als Abhängigkeiten, wodurch es sich auch für minimale Systeme eignet. Auch andere Anbieter als Let’s Encrypt sind möglich, da das genutzte ACME Protokoll als offener RFC-Standard vorliegt.

Installation und Registration

Die erste Installation erfolgt denkbar einfach mit pkg install dehydrated. Die für die Konfiguration wesentlichen Dateien liegen in /usr/local/etc/dehydrated.

Um die Dienste von Let’s Encrypt nutzen zu können, müssten die „terms of service“ akzeptiert werden. Diese können, bevor das erste Zertifikat bezogen wird, auf der Internetseite von Let’s Encrypt eingesehen werden. Einen direkten Link dorthin bekommt man auch, indem man einfach dehydrated --register aufruft. Diese Bedingungen können dann mit dehydrated --register --accept-terms akzeptiert werden. Hierbei werden die Informationen über die Registrierung sowie ein privater Schlüssel unter /usr/local/etc/dehydrated/accounts abgelegt.

Konfiguration

Die Konfigurationsdateien für dehydrated liegen unter /usr/local/etc/dehydrated. Es empfiehlt sich config.sample zu config und hook.sh.sample zu hook.sh zu kopieren, da hier in den .sample Dateien bereits viele, hilfreiche Vorarbeit und Kommentare angelegt sind. Die domains.txt kann auch neu als leere Datei angelegt werden, da diese in dem hier beschriebenen Fall sehr übersichtlich ist. Die domains.txt.sample verbleibt aber auch hier unmodifiziert als zukünftige Referenz.

Als Erstes werfen wir einen Blick auf die Datei domains.txt. Hier werden alle Domänen angegeben, für die ein Zertifikat benötigt wird. Für jede angegebene Zeile wird ein Zertifikat erstellt, und die erste angegebene Domäne pro Zeile wird der primäre Eintrag (Common Name) für das Zertifikat. Danach folgen, mit Leerzeichen getrennt, die Aliase (Alt Name). Für das aktuelle Beispiel wählen wir für den Webserver ein Zertifikat mit unserer Domäne, sowie allen 3rd Level Domains auf denen Webseiten gehostet werden. Der Mailserver benötigt kein so umfangreiches Zertifikat. Hier reicht ein Zertifikat für mail.antei.de aus. Dies führt zu folgenden Einträgen:

antei.de www.antei.de blog.antei.de
mail.antei.de

Dehydrated weist sich gegenüber dem Let’s Encrypt Server als berechtigt aus, ein Zertifikat für die entsprechende Domain signieren zu lassen, indem es eine s.g. „Challenge“ bezieht und die Antwort darauf über einen Webserver ausliefert, der auf Port 80 läuft. Dabei erstellt dehydrated selbst lediglich die Antwort und legt sie in einer Datei ab. Die eigentliche Auslieferung übernimmt in diesem Fall der nginx. Dazu muss dehydrated die Antwort an einer Stelle ablegen, die der nginx erreichen kann. Dies lässt sich in config über die Variable WELLKNOWN konfigurieren:

WELLKNOWN="/zroot/iocage/jails/www/root/usr/local/www/dehydrated"

Der nginx soll die von dehydrated erzeugten Dateien nun unter dem Prefix /.well-known/acme-challenge ausliefern. Dazu ist im nginx für alle Domains die folgende Konfiguration einzufügen.

location /.well-known/acme-challenge {
        alias /usr/local/www/dehydrated;
}

Um nach dem Beziehen eines Zertifikates dieses an die pasenden Stellen zu kopieren und die entsprechenden Dienste die neuen Zertifikate nutzen zu lassen, bietet dehydrated die Möglchkeit eigene Scripte an bestimmten Stellen im Ablauf ausführen zu lassen. Diese Scripte sind in einer Datei als Subroutinen gesammelt. In config muss diese Datei über die Variable HOOK benannt werden.

HOOK=${BASEDIR}/hook.sh

In der Datei hook.sh lassen sich nun weitere Schritte definieren, die beim Erneuern eines Zertifikats ausgeführt werden sollen. In diesem konkreten Fall sollen die passenden Zertifikatsdateien in die entsprechenden Verzeichnisse kopiert und die betroffenen Dienste dazu angewiesen werden, die Zertifikate neu zu laden. Hierfür werden in der Subroutine deploy_cert() folgende Zeilen hinzugefügt.

JAILS="/zroot/iocage/jails"
SSL="root/usr/local/etc/ssl"

case $DOMAIN in

    antei.de)
            echo "deploying certificate $CERTFILE to www jail..."
            cp $KEYFILE       $JAILS/www/$SSL/$DOMAIN/privkey.pem
            cp $CHAINFILE     $JAILS/www/$SSL/$DOMAIN/chain.pem
            cp $FULLCHAINFILE $JAILS/www/$SSL/$DOMAIN/fullchain.pem
            echo "reloading nginx"
            /usr/sbin/jexec ioc-www /usr/sbin/service nginx reload
            ;;

    mail.antei.de)
            echo "deploying certificate $CERTFILE to mail jail..."
            cp $FULLCHAINFILE $JAILS/mail/$SSL/fullchain.pem
            cp $KEYFILE       $JAILS/mail/$SSL/keyfile.pem
            echo "reloading dovecot"
            /usr/sbin/jexec ioc-mail /usr/sbin/service dovecot reload
            echo "reloading postfix"
            /usr/sbin/jexec ioc-mail /usr/sbin/service postfix reload
            ;;

    *)
            echo $DOMAIN not found
            ;;
esac

Hier handelt es sich um gewöhnliche Bash-Scripte. Ein detailierter Kommentar des Scripts übersteigt leider den Umfang dieses Artikels. Es sei aber darauf hingewiesen, dass die Zielverzeichnisse mit denen übereinstimmen müssen, die in den entsprechenden Mail- und Webservern konfiguriert sind. Die dafür nutzbaren Variablen sind in der hook.sh.sample ausführlich dokumentiert. Außerdem sollte beachtet werden, dass eine unter iocage angelegt Jail im System aus Sicht von jexec den prefix „ioc-“ erhält.

Die Datei hook.sh muss nun noch über die Dateirechte ausführbar gemacht werden. Sofern die Konfiguration der Systemdienste dahingehend angepasst wurde, dass die SSL Zertifikate geladen werden, sollte nun die Konfiguration soweit abgeschlossen sein, dass einem ersten Testlauf von dehydrated nichts im Wege steht.

Ein erster Aufruf von dehydrated lässt sich mit dehydrated -c (mit root rechten) erledigen. Sollten noch Probleme in der Konfiguration bestehen, lassen sich Anpassungen an selbiger auch bei bereits bestehendem Zertifikat mit dehydrated -c -x testen. Der Schalter -x erzwingt hier das erneuern eines Zertifikates und damit das Durchlaufen der damit verbundenen Automatismen, auch wenn das Zertifikat noch länger als 30 Tage gültig ist.

Zu guter Letzt sollte sicher gestellt sein, dass dehydrated regelmäßig aufgerufen wird, um bald ablaufende Zertifikate zu erneuern. Dies lässt sich beispielsweise über das Eintragen folgender Zeile in der /etc/periodic.conf erreichen.

weekly_dehydrated_enable="YES"

Abschließend sei noch darauf hingewiesen, dass über die vielfältigen hooks in der hook.sh weitreichende weitere automatisierungen möglich sind. Denkbare nächste Schritte wären das versenden von Hinweismails beim erfolgreichen bzw. missglückten erneuern eines Zertifikates. Außerdem lassen sich Challenges nicht nur über einen Web- sondern auch über einen DNS-Server beantworten. Letzteres ist die aktuell einzige Möglichkeit ein Wildcard-Zertifikat zu beziehen, sollte das gewünscht sein.