Da HAProxy ein wirklich dankbarer Helfer in vielen Lagen ist, sollen an dieser Stelle ein paar Erkenntnisse zur weiteren Verwendung dokumentiert werden.
Lets Encrypt HAProxy Setup
Laufen Services in K8s oder Docker und stellen diese ein Webinterface o.ä. bereit, das abgesichert werden soll, ist dies nicht immer ganz einfach. In der Regel kann man nicht einfach in den entsprechenden Container springen und dort den certbot installieren – selbst wenn doch, wäre er dann auch recht bald wieder weg. Das selbe gilt für die vom Certbot erzeugten Zertifikate.
Außerdem sind die Container vielleicht nicht direkt vom Internet aus erreichbar, oder hören innerhalb von K8s oder Docker Swarm auf andere Namen und IP Adressen. Es ist daher gängig Zertifikate auf dem Host abzulegen und die Pfade als Parameter beim Start des Containers zu übergeben. Das funktioniert aber nur dann mit überschaubarem Aufwand, wenn man ein passendes Zertifikat mit einer langen Laufzeit erworben hat. Mit Lets Encrypt Zertifikaten kann sowas hingegen zu einer Dauerbeschäftigung werden, was wenig Sinn macht.
Ein deutlich einfacherer Weg kann es daher sein, Services im internen Netz unverschlüsselt bereitzustellen und den Datenverkehr nur dann zu verschlüsseln, wenn er das interne Netzwerk verlässt. Hier kommt HAProxy ins Spiel. Das Ziel ist es, alle Services an das interne Netz zu binden und diese für Anfragen von außen nur über den HAProxy verfügbar zu machen.
In diesem Fall ist es ausreichend, wenn die SSL Verschlüsselung beim HAProxy endet. Folglich muss nur dieser ein valides Zertifikat haben. Im Hintergrund kann alles hoch- und runterskalieren, oder von einer Maschine zur anderen wandern, ohne irgendwelche Seiteneffekte bez. Zertifikatsgültigkeit zu verursachen.
Allerdings läuft auf dem HAProxy erstmal kein Webserver, weswegen ein paar kleine Tricks notwendig werden.
Certbot einrichten und Zertifikate erstellen
apt -y install bc git mkdir -p /etc/haproxy/cert mkdir -p /opt/letsencrypt git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
Nun die haproxy.conf editieren um folgende Einträge (sinngemäß) zu integrieren:
frontend skgmCache bind 116.202.109.112:80 mode http acl lets_encrypt path_beg /.well-known/acme-challenge/ # <- Diesen Pfad versucht lets encrypt bei der Verifizierung zu erreichen use_backend lets_encrypt if lets_encrypt # <- Wenn dieser Pfad abgefragt wird, soll ein anderes Backend genutzt werden default_backend cache backend cache mode http http-request set-header X-Forwarded-For %[src] balance leastconn option tcp-check server CacheBE01.skgm.de 116.202.108.28:80 check fall 3 rise 2 server CacheBE02.skgm.de 78.46.194.99:80 check fall 3 rise 2 backend lets_encrypt # <- Dieses Backend existiert nur temporär während der Certbot läuft mode http server local localhost:60001
Den HAProxy durchstarten.
systemctl restart haproxy
Nun den Certbot laufen lassen (Domain anpassen):
cd /opt/letsencrypt/ ./letsencrypt-auto certonly --domains CHANGEME.NOW.XXX --renew-by-default --http-01-port 60001 --agree-tos cat /etc/letsencrypt/live/CHANGEME.NOW.XXX/fullchain.pem /etc/letsencrypt/live/CHANGEME.NOW.XXX/privkey.pem > /etc/haproxy/cert/CHANGEME.NOW.XXX.pem
In einem Script um einen zyklischen renew zu triggern, kann das gleiche Vorgehen genutzt werden.
Erneut die haproxy.conf editieren und folgenden Eintrag (sinngemäß) integrieren:
frontend skgmCacheSecure bind 116.202.109.112:443 ssl crt /etc/haproxy/cert/ mode http http-request set-header X-Forwarded-For %[src] reqadd X-Forwarded-Proto:\ https option http-server-close default_backend cache
Ggfs. (fast immer) macht es nun Sinn, den Eintrag für das unverschlüsselte Frontend jetzt anzupassen, damit die dahinterliegenden Services nur noch verschlüsselt über das Internet kontaktiert werden können.
Service Config Beispiele für haproxy.conf
Generischer Webservice mit SSL Terminierung am Proxy
frontend skgmCache bind 116.202.109.112:80 mode http acl lets_encrypt path_beg /.well-known/acme-challenge/ use_backend lets_encrypt if lets_encrypt frontend skgmCacheSecure bind 116.202.109.112:443 ssl crt /etc/haproxy/cert/ mode http http-request set-header X-Forwarded-For %[src] reqadd X-Forwarded-Proto:\ https option http-server-close default_backend cache backend cache mode http http-request set-header X-Forwarded-For %[src] balance leastconn option tcp-check server CacheBE01.skgm.de 116.202.108.28:80 check fall 3 rise 2 server CacheBE02.skgm.de 78.46.194.99:80 check fall 3 rise 2 backend lets_encrypt mode http server local localhost:60001