Lokale Entwicklung

Immer mehr Anwendungen setzten SSL voraus, um richtig zu funktionieren. Die Möglichkeit selbstsignierte Zertifikate zu nutzen kann man in Betracht ziehen, ist aber der Erfahrung nach auch nicht die Lösung, das es viele zusätzliche Probleme bereitet.

Also wäre es gut auch auf einem Entwicklungsrechner mit TLS/SSL zu arbeiten.

NginX Reverse Proxy

Um die lokalen Server mit SSL abzusichern benötigt man nicht viel. Im Grunde braucht man zunächst ein Wildcard Zertifikat. Wenn dieses vorliegt, dann ist die größte Hürde bereits genommen.

Was ihr noch braucht ist Docker, aber das sollte mittlerweile auch auf jedem Rechner vorhanden sein.

Konfiguration

Erstellt ein neues Verzeichnis und kopiert den privaten Key und das fullchain.cer z.B. von LetEncrypt mit in das Verzeichnis.

Erstellt eine docker-compose.yaml mit folgendem Inhalt:

version: "3.5"
services:
  reverseproxy:
    image: nginx
    ports:
      - "443:443"
    restart: always
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./fullchain.cer:/etc/nginx/fullchain.cer
      - ./private.key:/etc/nginx/private.key

Was nun noch fehlt ist die NginX Konfiguration. Dieses ist auch recht einfach gehalten. Speichert die nginx.conf so ab:

user nginx;
worker_processes 1;

pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

error_log /dev/stdout debug;

http {
    # https redirect
    server {
        listen 80;
        server_name "~^k8s-.+\.domain\.de$";
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name "~^k8s-.+\.domain\.de$";

        ssl on;
        ssl_certificate     /etc/nginx/fullchain.cer; # fullchain
        ssl_certificate_key /etc/nginx/private.key;   # private key

        #
        # Serve Kubernetes cluster. Forward to ingress controller
        #
        location /
        {
            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;

            # static IP address of K3D cluster
            proxy_pass              http://192.168.2.100:4000/; # ACHTUNG: Nicht localhost!!! Das wäre der Docker Container.

            proxy_read_timeout      600s;
            proxy_send_timeout      600s;
        }
    }
}

Hier muss die Host Addresse (also die IP des Entwicklungsrechner) und der Port angegeben werden. In dem Beispiel ist es ein lokaler Kubernetes Cluster. Über die RegEx nimmt NginX im Server Block alle Host der Doamin entgegen.

DNS

Zu guter letzt müsst ihr für DNS Einträge sorgen. Am einfachsten über die /etc/hosts Datei. Dann sollte ein gesicherter Aufruf mit HTTPS möglich sein.

LDAPS mit SSL

Selbstsignierte Zertifikate

Das Problem mit den selbstsignierten Zertifikaten ist, dass man überall Probleme bekommt, wenn man SSL nutzen möchte. Hier ganz konkret die Nutzung eines Docker Containers mit Sonarqube. Es ist ohne viel Aufwand zu betreiben, nicht möglich Sonarqube zu überreden mit dem OpenLDAP Server mit SSL zu kommunizieren. Es müsste erst ein Truststore erstellt und dann in dem Container propagiert werden. Diese oder ähnliche Probleme bekommt man immer wieder.

LetsEncrypt Zertifikat

Wer sich ein Wildcard Zertifikat von LetsEncrypt für seine Domäne ausgestellt hat, der kann dieses auch nutzen um OpenLDAP per SSL abzusichern. Dieses hat dann den Vorteil, dass die oben beschriebenen Probleme nicht auftreten und das Leben viel einfacher wird.

Die Konfiguration von OpenLDAP

Die Verwendung der LetsEncrypt Zertifikate ist eigentlich nicht besonders schwierig. Es muss nur die Konfiguration angepasst werden. Editieren sie die Datei /etc/openldap/slapd.conf und passen sie die SSL Konfiguration an:

# Certificate/SSL Section
TLSCipherSuite DEFAULT
TLSCertificateFile /etc/openldap/ssl/cert.pem
TLSCertificateKeyFile /etc/openldap/ssl/privkey.pem
TLSCACertificateFile /etc/openldap/ssl/chain.pem
TLSCACertificatePath /usr/share/ca-certificates/trust-source

Damit das funktioniert, müssen aus dem LetsEncrypt live Verzeichnis die Dateien kopiert werden. Es muss für den User unter dem der OpenLDAP Server ausgeführt wird (meisten ldap) lesbar sein.

Konfiguration einlesen

Die Konfiguration muss nun in die Datenbank übernommen werden, da OpenLDAP die Konfigurationsdatei nicht mehr direkt einliest. Ich verwende immer ein kurzes Skript welches den Dreisatz für mich ausführt:

#!/bin/bash

# remove old config
rm -rf /etc/openldap/slapd.d/*

# create new files
slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d/

# chown to ldap:ldap
chown -R ldap:ldap /etc/openldap/slapd.d

Führen sie das Skript aus, damit die geänderte Konfiguration übernommen wird.

Server Test starten

Da bei Fehlern die Meldungen in Journal sehr dürftig sind, ist es besser wenn man den Server zum Testen auf der Konsole startet.

slapd -u ldap -g ldap -h ldaps://ldap.XXX.org:636 -d Config,Stats

Wichtig: Passt hier die Domain nicht, dann gibt es einen daemon: bind(8) failed errno=98 (Address already in use). Das Starten mit ldaps:/// reicht nicht !!!

Das Zertifikat von OpenLDAP überprüfen

Ist der Server gestartet, so bietet es sich an schnell mit openssl das Zertifikat zu überprüfen.

openssl s_client -connect ldap.XXX.org:636

Änderung Systemd

Zuletzt muss die override.conf von dem slapd.service muss nun angepasst werden. Danach starten sie per

systemctl start slapd.service

OpenLDAP neu.

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"