Motivation
Ich habe einige Domains in Betrieb, mit verschiedensten Anwendungsfällen. Die meisten meiner per Web erreichbaren Services sollten per TLS erreichbar sein - einfach weil es heutzutage Standard ist, und weil es keinen wesentlichen Mehraufwand darstellt. Zusätzlich ist das ganze TLS-Setup ein tolles Learning für mich und für die Automatisierung von Diensten.
In einem früheren Blog Post habe ich bereits beschrieben wie ich Wildcard Zertifikate per DNS Challenge erzeuge. Dafür muss der Server, der das Zertifikat ausstellt, noch nicht einmal aus dem Internet erreichbar sein.
Manchmal ist es dann aber doch praktisch, die ganz “normale” HTTP Challenge zu nutzen. Das wollte ich also einrichten, allerdings mit einer wesentlichen Einschränkung: Alle Zertifikate sollten auf einem zentralen Server gemanaged werden.
Die wesentliche Challenge dabei: Ich habe mehrere Hosts die öffentlich verfügbar sind, und mit verschiedenen benötigten Zertifikaten. Trotzdem sollten die HTTP Challenges zentral gemanaged werden.
Ein Wort zur Security
TLS Zertifikate sollten eigentlich nicht verteilt werden, insbesondere der private Schlüssel zu einem Zertifikat sollte in einer kontrollierten Umgebung bleiben. Das schaffe ich in meinem Setup auch, weil auf den Servern auf denen meine Zertifikate leben ausschließlich ich Shell-Zugriff habe. Zusätzlich sind die meisten davon sowieso nur aus meinem lokalen Netzwerk erreichbar.
nginx Setup
Schlussendlich war die Lösung überraschend einfach: Wenn ich ein TLS Zertifikat für subdomain.tech-tales.blog
per HTTP Challenge bei Let’s Encrypt anfordere, wird erwartet, dass ein bestimmter Inhalt unter http://subdomain.tech-tales.blog/.well-known/acme-challenge/something
gefunden wird. Ich muss also nur diese Anfrage an meinen Zertifikat-Server weiterleiten!
Ich nutze fast überall nginx als Reverse Proxy, und habe meine Konfiguration folgendermaßen angepasst:
server {
listen 80 default_server;
listen [::]:80 default_server;
# ...
location /.well-known/acme-challenge/ {
proxy_pass http://ip.of.cert.server/.well-known/acme-challenge/;
}
}
Vorher hatte ich HTTP Requests einfach ungesehen auf HTTPS umgeleitet - eben weil meine Services ja sowieso alle HTTPS sprechen. Diese Regel ist hiervon die Ausnahme: Wenn Let’s Encrypt mir ein Zertifikat ausstell, erwartet es nicht dass ich bereits ein TLS Zertifikat habe.
Mein Zertifikat-Server hat auch eine neue nginx-Konfiguration bekommen:
server {
listen 80;
server_name ip.of.cert.server;
root /var/www/acme-http;
}
Konfiguration von acme.sh
Jetzt muss ich dem Zertifikat-Server, oder genauer gesagt, acme.sh
, nur noch mitteilen wo die Challenge-Datei abgelegt werden soll. Das war aber nicht schwer:
acme.sh --issue --server letsencrypt_test -d subdomain.tech-tales.blog --webroot /var/www/acme-http/
Dadurch passiert das Folgende:
acme.sh
fragt um ein TLS Zertifikat fürsubdomain.tech-tales.blog
an.- Dazu soll es
/var/www/acme-http/
als Webroot verwenden. acme.sh
bekommt von Let’s Encrypt ein Challenge File und legt dieses in/var/www/acme-http/.well-known/acme-challenge/something
ab.- Let’s Encrypt stellt eine Anfrage an
http://subdomain.tech-tales.blog/.well-known/acme-challenge/something
. Der öffentlich verfügbare Server erhält diese Anfrage und leitet sie an den Zertifikat-Server weiter; der Zertifikat-Server findet die korrekt platzierte Datei und liefert sie aus. - Let’s Encrypt ist glücklich und ich erhalte mein Zertifikat!
- Jetzt muss ich das Zertifikat nur noch zurück an den öffentlich verfügbaren Server ausspielen. Darüber schreibe ich vermutlich ein anderes Mal.
Fazit
Mir gefällt das Konzept, alle TLS Zertifikate an einem Ort zu sammeln. Anderenfalls verliere ich schnell den Überblick, welches Zertifikat wo ausgestelt wird. Und mit diesem Setup kann ich das bereits existierende Setup für DNS Challenges um HTTP Challenges erweitern!