Geuni/ April 28, 2020/ Deutsch/ 0Kommentare

Im ersten Teil „ReverseProxy – Teil 1? Was ist das? Wie hilft der mir?“ habe ich gezeigt, wie man sich in einem Docker-Container einen ReverseProxy aufbauen kann und seine ersten Anwendungen darüber bereitstellt, sowie eine Authentifizierung darüber durchführt. Jetzt wollen wir uns mal darauf fokussieren wie wir endlich ein SSL-Zertifikat kostenlos einbinden und erneuern können, sowie auf was man bei TLS/SSL noch so achten muss, damit es auch sicher ist.

1) Was wollen wir hier erreichen?

Wir wollen unsere Services über unseren Reverseproxy mit TLS absichern und möglichst alle „Betriebstätigkeiten“ automatisieren, sodass wir damit kaum mehr was zu tun haben.

2) Welche Anforderungen haben wir?

Wir wollen ein SSL-Zertifikat in unserem Apache einbinden, die Erneuerung des Zertifikats automatisiert ablaufen lassen und eine gängige, sichere Konfiguration für unsere Dienste bzgl. SSL/TLS.

3) Wie wollen wir das erreichen?

Die Grundlagen mit unserem ReverseProxy haben wir schon gebaut, jetzt brauchen wir nur noch einen weiteren Container mit einem CertBot der das Zertifikat besorgt und erneuert. Natürlich müssen wir CertBot dazu mit dem Apache-ReverseProxy-Container integrieren.

4) CertBot – Vorbereitung auf Verzeichnisebene

Im Bereich von Docker-Containern kann man praktisch alle auf Kommandozeilen ebene machen, was wiederum heißt, das sehr viel automatisierbar ist. Deshalb werden wir uns einen Befehl zusammenbauen, der den Container aufsetzt, kurz laufen lässt und wieder entfernt. Damit das funktioniert, müssen wir ein Paar Ordner vorbereiten, die richtigen Berechtigungen vergeben und etwas in unseren vHosts in der Apache-Konfiguration ändern. Fangen wir mit den Ordnern an.

Wir legen im Freigabeordner/Share „Container“ einen Ordner mit dem Namen „letsencrypt“ an (wenn wir das nicht schon zuvor haben). In diesem Ordner kommt noch ein Ordner rein mit dem Name „data“. Jetzt brauchen wir noch einen Ordner in „data“ mit dem Namen „.well-known“ (den Punkt nicht vergessen, der ist wichtig). Darin dann noch einen Ordner anlegen mit dem Namen „acme-challenge“. Sollte die Anlage der Ordner über den Windows-Explorer nicht funktionieren, müsst ihr das mittels des „mkdir“ Befehls über eine SSH-Verbindung auf eurem NAS oder per CMD in Windows probieren.

mkdir /share/Container/letsencrypt/
mkdir /share/Container/letsencrypt/data/
mkdir /share/Container/letsencrypt/data/.well-known
mkdir /share/Container/letsencrypt/data/.well-known/acme-challenge

Jetzt fügen wir am Anfang in unserer Apache-Konfiguration wo unsere vHosts (\\\Container\apache\apache\conf\vhosts\.conf) beschrieben sind diese Zeilen ein:

########################
#CertBot Configs for all!
########################
#Setze einen Alis
Alias /.well-known/acme-challenge/ "/letsencrypt/data/.well-known/acme-challenge/"
#bestimme das Verzeichnes
<Directory "/letsencrypt/data/.well-known/acme-challenge/">
    #erlaube jeder IP das Verzeichnis anzusprechen
    Require all granted
    #Der Server hält für das Verzeichnis einen Index vor und ist in der Lage Symbolische Links im Dateipfad zu verfolgen
    Options -Indexes -FollowSymLinks
    #.htaccess dateien in denen andere Einstellungen für Directories vorhanden sein können werden durch das "none" ignoriert"
    AllowOverride None
</Directory>

Das ist die allgemeine Funktion dass CertBot auf jedem vHost den ihr weiterhin anlegen werdet! Das ist praktisch die Integration von CertBot mit eurem Apache.

Diese Zeilen bewirken, dass wir erstmal einen Alias anlegen, um hinter unserer Domain oder allen Sub-Domains in den Pfad „/.well-known/acme-challenge/“ browsen können. Dieser Pfad, den wir in den Browser eingeben wird im Apache-ReverseProxy-Container (Vorsicht: das spielt sich gerade gedanklich nicht im CertBot-Container ab!) auf den lokalen Pfad zur Laufzeit „/letsencrypt/data/.well-known/acme-challenge/“ umgemünzt.

Damit das geht, muss im Apache-Container natürlich auf der Root der Ordner verfügbar sein (Stichwort: YML-Datei und Volumes). Das werden wir später noch testen, da wir hier auch mit Berechtigungen spielen müssen.

5) CertBot – Verzeichnisberechtigungen

Wer diesen kleinen Streich im Kopf verstanden hat, weiß jetzt, dass wir unsere „Apache.yml“ wahrscheinlich nochmal prüfen sollten, ob wir ein Volume drin haben, dass auf der Root des Apache-Containers überhaupt einen Ordner mit dem Namen „letsencrypt“ hat. Dazu gibt es zwei Wege wie wir das testen;

  • 2) Wir führen einen „ls“-Befehl mittels SSH im Apache-Docker-Container aus, um zu sehen welche Ordner zur Laufzeit vorhanden sind:
docker exec apache ls 

Jetzt müssen wir auf diese komisch benannten Ordner („well-known“, „acme-challenge“) noch die Rechte ändern, denn darin muss jeder Administrator vom Server schreiben können. Sonst funktioniert CertBot nicht. Das machen wir einfach durch ein CHMOD und ein CHOWN mit dem Parameter rekursiv.

# ändern des Eigentümers und der Gruppe
chown -R admin:administrators /share/Container/letsencrypt/
# gewähre dem Eigentümer und der Gruppe volle Rechte, Jedem aber keine
chmod 770 /share/Container/letsencrypt/
# gewähre dem Eigentümer und der Gruppe volle Rechte, Jedem aber keine
chmod 770 -R /share/Container/letsencrypt/data/

In diesem Ordner soll nach dessen Funktion nur eine temporäre Datei vom CertBot abgelegt werden, die LetsEncrypt gegencheckt, damit man ein SSL-Zertifikat ausstellt. Sollte nun jemand dort also Daten ablegen,(wohl bemerkt, das kann nur ein Innentäter! Das kann niemand aus dem Internet!) hat dieser schlichtweg nichts von. Also stellt für uns, diese Konfiguration erstmal kein Problem dar. Sollte alles funktioniert haben liefert ein „ls -al“ etwa folgendes Ergebnis.

[~] # ls -al /share/Container/letsencrypt/
total 76
drwxrwxrwx 13 admin administrators 4096 2019-06-22 10:36 ./
drwxrwx--- 14 admin administrators 4096 2019-06-22 09:34 ../
drwxrw-rw-  4 admin administrators 4096 2019-04-22 20:15 accounts/
drwxrwx---  3 admin administrators 4096 2019-04-28 12:57 archive/
drwxrw-rw-  2 admin administrators 4096 2019-04-28 12:57 csr/
drwxrwx---  3 admin administrators 4096 2019-04-28 12:38 data/
drwxrw-rw-  3 admin administrators 4096 2019-04-21 11:21 etc/
drwxrw-rw-  2 admin administrators 4096 2019-04-28 12:57 keys/
drwxrwx---  3 admin administrators 4096 2019-04-28 12:57 live/
drwxrw-rw-  2 admin administrators 4096 2019-06-20 21:49 log/
drwxrw-rw-  2 admin administrators 4096 2019-04-28 12:57 renewal/
drwxrw-rw-  5 admin administrators 4096 2019-04-22 19:55 renewal-hooks/
-rwxrw-rw-  1 admin administrators   64 2019-01-01 21:29 .updated-options-ssl-apache-conf-digest.txt*
drwxrw-rw-  2 admin administrators 4096 2019-04-21 11:21 var/

Wichtig sind hier gerade die Angeben für das Verzeichnis „data/“.

Hier würde ich jetzt einen Test empfehlen! Mit diesem ganzen Volumes in Docker-Containern kann das ganz schön kompliziert sein. Apache-Docker einmal neustarten (geht nach unserem Weg nur mittels SSH):

docker restart apache

Wir sollten jetzt noch eine TXT-Datei mit beliebigem Inhalt im Ordner „..\Container\letsencrypt\.well-known\acme-challenge\“ anlegen. Jetzt mal versuchen eine unserer konfigurierten Domains im Browser aufzurufen und am ende „/.well-known/acme-challenge/.txt“ anhängen. Sollte das nicht gehen haben wir noch ein Problem (Bedenke Browsercaching, ein wechsel kann an so einer Stelle manchmal helfen keine Seiteneffekte als Fehler zu interpretieren). Ziel dieses Tests ist, dass wir über eine Domain von uns eine Datei im Ordner „/.well-known/acme-challenge/“ aufrufen können. Wenn das geht, dann sind unsere Laufwerksmappings korrekt und CertBot sollte dann auch auf die Dateien zugreifen können bzw. zur Laufzeit die notwendigen Dateien erstellen können.

Wenn ihr jetzt den Inhalt eurer Datei seht, dann hat das schon mal funktioniert und CertBot könnte damit die Challenge machen und eurer Domains validieren. Dafür müssen wir diesen nur aufsetzen.

6) CertBot – Dry-Run Zertifikate!

Bei Lets-Encrypt solltet ihr, so lange ihr eure „CertBot-Kommandozeile“ nicht perfekt habt, immer einen „Dry-Run“ machen, denn je Domain gibt es sog. Rate-Limits. Heißt, wenn ihr zu oft etwas falsch macht, sperrt euch Lets-Encrypt für eine Woche und ihr könnt warten bis ihr es erneut versuchen könnt! Deshalb, immer beim testen auf den Parameter „Dry-Run“ achten. In SSH tippt ihr folgenden Befehl ein (natürlich ersetzt ihr die notwendigen Stellen durch eure Konfiguration):

docker run -it --rm -v /share/Container/letsencrypt:/etc/letsencrypt -v /share/Container/letsencrypt/data:/data/letsencrypt certbot/certbot certonly --non-interactive --webroot --webroot-path=/data/letsencrypt -d <domain>.<tld> -d <subdomain>.<domain>.<tld> --email <name>@<domain>.<tld> --agree-tos --dry-run

Damit wir mal verstehen was wir hier machen. „docker run“ sagt das ihr einen Container ausführen wollt, „-it“ heißt „i“=“interactive“ und „t“=“terminate“, bewirkt also, dass der Container interaktiv ausgeführt wird und nach seinem Lauf beendet. „–rm“ steht dann dafür, dass er nach dem Lauf wieder gelöscht wird. Mit „-v“ kommen wie in der YML-Datei die Volume-Mappings. Nach einem Leerzeichen des letzten Volumes steht der Name des Images (diese sind im Docker-Hub angegeben). Jetzt folgt der eigentlich CertBot-Befehl der im Container zur Laufzeit ausgeführt wird.

Hier würde man eigentlich erst als Befehl (wenn man CertBot in einem OS installiert) wieder CertBot erwarten, da der Container aber nichts anderes kann, ist das praktisch schon ausgeführt und wir parametrisieren den schon laufenden CertBot mit dem erstem Parameter „certonly“, sagen diesem dann dass wir bitte nicht interaktiv sind (also wir beantworten so manch eine Frage nicht!) mit „–non-interactive“ und sagen dann, dass wir im sog. WebRoot-Mode arbeiten wollen und wo unser „Web-Root“ im Beispiel ist (dafür sind die komisch benannten Ordner zuvor). Mit „-d“ geben wir unsere Domain an. Jeder weiter „-d“-Parameter gibt einen sog. „alternative-Name“ im SSL-Zertifikat an. Hier können jetzt einfach andere Domains genommen werden (würde ich nicht empfehlen), aber auch alle Sub-Domains die wir haben.

Letztlich geben wir noch eine E-Mail an und sagen, dass wir den Benutzerbestimmungen zustimmen und das wichtige „–dry-run“ nicht vergessen, denn wir wissen noch nicht ob das funktioniert!

Wenn wir den Befehl abfeuern, sollte in etwa sowas herauskommen, wenn es funktioniert!

Wenn Fehler kommen, dann müsst ihr ggf. die Rechte anpassen, dass ist meist das Problem! CertBot sollte euch aber immer den HTTP-Error-Code ausgeben, damit erhaltet ihr gute Anhaltspunkte was nicht geht.

[~] # ....  --agree-tos --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Cert not due for renewal, but simulating renewal for dry run
Renewing an existing certificate
Performing the following challenges:
...
Using the webroot path /data/letsencrypt for all unmatched domains.
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
 - The dry run was successful.

Wenn es funktioniert, dann den gleichen Befehl nur ohne den Parameter „–dry-run“ ausführen und ihr bekommt euer Zertifikat!

Solltet ihr euer Zertifikat haben, könnt ihr das prüfen im Ordner \\\Container\letsEncrypt\live\ dort sollte jetzt ein Ordner sein mit dem ersten „-d“-Parameter Wert, also wahrscheinlich euer Root-Domain. Dort drin sollten jetzt ein paar Dateien liegen wie eine chain.pem eine key.pem etc.

7) ReverseProxy vHost – HTTPs Redirects

Oben haben wir bis jetzt immer nur mit HTTP gespielt. Wir haben bis jetzt noch nichts mit HTTPs versucht. CertBot braucht für die Validierung einer Website auch nur HTTP, deshalb muss HTTP zumindest für CertBot immer offen bleiben. Wir wollen aber nicht, dass irgendwer anders weiterhin über HTTP zugreift, jeder andere soll deshalb zwanghaft auf HTTPs weitergeleitet werden.

Damit wir jetzt sicher auf unsere Seiten per HTTPs zugreifen können, uns aber gleichzeitig nicht den CertBot versauen, müssen wir unserem Apache sagen, dass fast alle Anfragen die HTTP sind auf HTTPs umgemünzt werden sollen, aber genau die vom CertBot nicht! Dazu tragen wir in unserer vHosts-Datei unter dem Alias-Block die folgenden drei Zeilen ein!

########################
#HTTP rewrites
########################
#Einschalten der Engine
RewriteEngine on
#Bedingung: Wende Rewrites erst an, wenn die angeforderte Datei eine gültige ist!
RewriteCond %{REQUEST_FILENAME} !-f
# Wenn jetzt bei einer gültigen Datei im Pfad "well-known" auftaucht, mache nichts und beende alle weiteren Rewrites!
RewriteRule ^\.well-known/.+ - [END]
# Wenn kein "well-known" vorkahm, schreibe alles auf HTTPs um
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]

Zum verstehen: erst schalten wir die RewriteEngine an. Dann definieren wir die Bedingung (RewriteCond), dass immer wenn eine Datei angefordert wird die es gibt, die erste Regel angewendet wird (erlaubt nur Dateien mit dem URL-Anteil „well-known“), welche die Datei per HTTP zugreifen lässt. Wenn die Datei per HTTP nicht gefunden wird, leite alles auf HTTPs um und ignoriere das jemand eine Datei aus „.well-known“ haben wollte. Das im Groben, wie diese Zeilen funktionieren, im Detail sind diese wesentlich komplizierter! Ich erkläre aber erstmal nicht, was das genau heißt und verweise auf die Apache Dokumentation für die RewriteEngine.

8) ReverseProxy vHost – Global HTTPs config

Jetzt kommen wir zu den eigentlichen SSL-Parametern die wir einmal für alle vhosts konfigurieren und dann jeweils innerhalb jeden vHosts (Code weiter unten mit Kommentaren).

SSL-Stapling, darum geht es in den ersten 4 Zeilen nach dem Kommentar im Code. Es ist dämlich das es SSL-Stapling heißt, denn es bezeichnet die Funktion, Zertifikate gegenüber mehrere Zertifizierungsstellen auf dessen Gültigkeit zu prüfen, was kurz OCSP (Online Certificate Status Protocol) genannt wird. In der vierten Zeile, in der das Cachingverzeichnis angegeben wird, wird beschrieben, dass hier mit dem Protokoll „shmcb“ als sog. „Shared Object Cache“ auf einen Pfad zugegriffen wird.

SSLPassPhraseDialog bezeichnet die Methode mit der Apache beim Start den verschlüsselten Private-Key des SSL-Zertifikats lokal entschlüsselt. Hier könnte man z.B. ein anderes Programm einbinden wenn man hier mit Service-Accounts und ähnlichem arbeiten will. Die nächsten zwei Parameter sind wieder Caching-Funktionen für laufende SSL-Sitzungen.

WICHTIG: Alle Pfade die ihr hier angebt, werden aus Sicht des Apache-ReverseProxy-Containers ausgeführt. Das verwirrt immer gern wenn man vergessen hat wie die Mappings im Container waren! Hier jetzt der Code und Kommentare darüber, sollte man das gerade nicht zusammen bekommen.

######## SSL CONFIGS
# schalte die SSL-Enginge an
SSLUseStapling on
# Setze den OCSP-Responder-Timeout auf 5 sekunden
SSLStaplingResponderTimeout 5
# Sende der CA keine Responder-Errors
SSLStaplingReturnResponderErrors off
# Cache die OCSP-Responses mittels shmbc im Pfad ...
SSLStaplingCache shmcb:/var/run/ocsp(128000)
# Nehme die Apache-Standard Methode um Private-Keys beim Serverstart zu entschlüsseln
SSLPassPhraseDialog  builtin
# definiere den Ort wo SSL-Caches abgelegt sind
SSLSessionCache "shmcb:/opt/bitnami/apache/logs/ssl_scache(512000)"
# Entferne SSL-Caches nach 300 Sekunden wenn diese ungenutzt sind
SSLSessionCacheTimeout  300

9) ReverseProxy vHost – vHost HTTPs config

So, jetzt haben wir oben mal die allgemeinen Parameter für SSL kurz beschrieben. Diese sind nicht vollständig! Sie sind aber für unseren Anwendungsfall hier erstmal ausreichend.

Jetzt gehen wir weiter zu unserem vHost. Diesen müssen wir jetzt auch noch für SSL/HTTPS fertig machen. Dazu setzen wir in unserem Beispiel erstmal den Port auf 8443. Das liegt schlicht weg an unserer Konfiguration, üblich wäre hier der Port 443.

Man könnte glauben das in der ersten Zeile der Name des vHost angegeben wird, nein, das passiert in der Zeile „Servername“. Da ist eure Domain einzusetzen, oder Subdomain. In der ersten Zeile „“ könntet ihr das „*“ durch eine IP ersetzen um ggf. andere Interfaces für die Bearbeitung des vHosts zu definieren. Danach machen wir die SSLEngine an und setzen einen Header um HTTP Strict Transport Security (HSTS) zu aktivieren, natürlich auch für alle Subdomains. HSTS ist ein Schutz für HTTPs der besagt, dass der Browser des Anwenders über eine bestimme Zeit (max-age) von der Seite nur HTTPs Verbindungen erlaubt. So werden sog. „Downgrade-Attacken“ oder „Session Hijacking“ Attacken unterbunden.

Danach definieren wir die erlaubten SSL-Protokolle. Da sagen wir, „all“ und exkludieren mit einem Minus alle die wir nicht wollen. In dem Beispiel machen wir alle aus, die alt sind und bekannte Schwächen haben. Da gehe ich jetzt nicht im Detail drauf ein, dazu empfehle ich zu googeln, denn da wird man schnell fündig welche Schwachstellen in den alten Protokollen enthalten sind (bspw. in TLS1.0).

Zu den Protokollen gehört es dann noch, dass man die sog. CipherSuits angibt. Das sind die im TLS-Protokoll eingesetzten Verschlüsselungsalgorithmen. Da gehe ich noch weniger drauf ein, denn hiermit kann man Bücher füllen! Wer das genauer verstehen will sollte auf Wikipedia anfangen mit dem Thema.

Nachfolgend in der Konfiguration kommt ein wichtiger Teil, indem wir sagen, dass die CipherSuits nur in der Reihenfolge abgearbeitet werden dürfen, wie diese angegeben sind. Das verhindert Downgrade-Attacken. Dann sagen wir noch das wir Kompression ausstellen, sowie Session-Tickets.

Jetzt geben wir noch an wo unsere Zertifikate liegen. Dabei ist zu bedenken, dass wir hier immer relativ aus dem Container hantieren. Dazu ggf. einen Blick in die YML-Datei unseres Apache-ReverseProxy-Containers machen und schauen, wo wir das Verzeichnis für LetsEncrypt eingebunden haben und natürlich wieder einmal die Berechtigungsstruktur prüfen, damit Apache die Dateien wirklich sehen und nutzen kann.

Alles auch noch als Kommentar im Code.

<virtualhost *:8443="">
	# Das ist der Name des vHosts welcher gleich der Domain oder Subdomain sein sollte
	Servername <domain>.<tld>
	
	# hier wird die SSL-Enginge für den vHost aktiviert
	SSLEngine on
	
	# Das ist die aktivierung vom sog. HSTS
	Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
	
	# definiert welche Protokolle wir für HTTPs zulassen
	SSLProtocol             all -TLSv1 -TLSv1.1 -SSLv2 -SSLv3
	
	# definiert die genutzten Verschlüsselungsalgorithmen
	SSLCipherSuite          'kEECDH+ECDSA kEECDH kEDH HIGH +SHA !aNULL !eNULL !LOW !MEDIUM !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !RC4'
	
	# definiert das die Verschlüsselungsalgorithem in der oben genannten Reihenfolge angewendet werden, von links nach rechts
	SSLHonorCipherOrder     on
	
	# deaktiviert die komprimierung von SSL Traffic
	SSLCompression          off
	
	# sorgt dafür das jede Sitzung ein Ticket bekommt
	SSLSessionTickets       off
	
	# Pfadangabe zum Zertifikat
	SSLCertificateFile      /letsencrypt/live/<domain>.<tld>/cert.pem
	
	# Pfadangabe zum Privateky
	SSLCertificateKeyFile   /letsencrypt/live/<domain>.<tld>/privkey.pem
	
	# Pfadangabge zur Zertifikatskette
	SSLCertificateChainFile /letsencrypt/live/<domain>.<tld>/chain.pem
	# quasi standarad zur bestimmung des originalen protokols
	RequestHeader 	append 	"X-Forwarded-Proto" "https"
	
	# zusätzliche Information das ursprünglich SSL in der Verbindung war
	RequestHeader 	set 	"X-Forwarded-Ssl" "on"
	<location "="">
		ProxyPass        http://xxx.xxx.xxx.xxx:8080/
		ProxyPassReverse http://xxx.xxx.xxx.xxx:8080/
	</location>
</virtualhost>

Zum Schluss setzen wir noch zwei X-Header, die von Browsern genutzt werden können, oder von Anwendungen. Diese sind im Internet (die zwei genutzten) quasi Standards und werden von vielen Anwendungen eingesetzt. Diese besagen nur, dass wir mit einem Reverse-Proxy SSL-Datenverkehr weiterleiten dürfen und das der ursprüngliche Verkehr HTTPs-Verschlüsselt ist. Ganz am Ende kommt wieder unser Location-Teil der das eigentliche Weiterleiten an den Service in unser „Backend“ darstellt.

Wir müssen jetzt noch prüfen, ob unser ReverseProxy auch wirklich auf unsere SSL-Zertifikats-Dateien zugreifen kann. Damit wir die Rechte auf die richtigen Ordner anwenden, sollte man ein wenig verstehen wie die Ordner von CertBot angelegt werden. CertBot legt nach unseren Konfiguration alle Daten im Order „\\\Container\letsencrypt“ an. Dort sehen wir mittels SSH folgende Ordner und deren Berechtigungen:

ls -al /share/Container/letsencrypt/
total 76
drwxrwxrwx 13 admin everyone       4096 2019-06-22 10:36 ./
drwxrwxrwx 14 admin administrators 4096 2019-06-22 09:34 ../
drwxrw-rw-  4 admin administrators 4096 2019-04-22 20:15 accounts/
drwxrwxrwx  3 admin everyone       4096 2019-04-28 12:57 archive/
drwxrw-rw-  2 admin administrators 4096 2019-04-28 12:57 csr/
drwxrw-rw-  3 admin everyone       4096 2019-04-28 12:38 data/
drwxrw-rw-  3 admin administrators 4096 2019-04-21 11:21 etc/
drwxrw-rw-  2 admin administrators 4096 2019-04-28 12:57 keys/
drwxrwxrwx  3 admin everyone       4096 2019-04-28 12:57 live/
drwxrw-rw-  2 admin everyone       4096 2019-06-20 21:49 log/
drwxrw-rw-  2 admin administrators 4096 2019-04-28 12:57 renewal/
drwxrw-rw-  5 admin administrators 4096 2019-04-22 19:55 renewal-hooks/
-rwxrw-rw-  1 admin administrators   64 2019-01-01 21:29 .updated-options-ssl-apache-conf-digest.txt*
drwxrw-rw-  2 admin administrators 4096 2019-04-21 11:21 var/

CertBot legt unter dem Ordner „live“ die aktuell gültigen Zertifikate an, und alle Zertifikate die er anfordert und signiert bekommt, im Ordner „archive“. Der Witz ist, dass unter „live“ immer nur symbolische Links auf die Dateien unter „archive“ liegen. Deshalb müssen wir beide Ordner mit den gleichen Berechtigungen versehen.

chmod 777 -R /share/Container/letsencrypt/live
chmod 777 -R /share/Container/letsencrypt/archive
chown admin:everyone -R /share/Container/letsencrypt/archive
chown admin:everyone -R /share/Container/letsencrypt/live

Das ist mit 777 leider recht viel an Rechten die man auf die Ordner live und „archive“ anwendet, aber scheinbar nicht anders möglich. Alle meine Versuche das hinzubekommen mit weniger Rechten zu lösen, sind bei mir gescheitert.

Jetzt sollte man am Ende natürlich nicht vergessen noch den Port 443 an eurem Router aufzumachen und (wie in unseren Beispiel oben) auf den internen Port 8443 umzuleiten, auf die IP des Apache-ReverseProxy-Containers. So kann man eure neue Website aus dem Internet erreichen. Wenn ihr gerade nicht wisst, wie das geht, schaut in Teil 1 nach, da steht es für Port 80 beschrieben und da ersetzt ihr einfach 80 durch 443, respektive 8443.

10) ReverseProxy vHost – HTTP vHost trotz HTTPs

Damit jetzt auch wirklich alles mit CertBot geht (ich bin ehrlich, das musste ich nachtragen) muss mindestens ein HTTP vHost im Apache verfügbar sein, den wir einfach irgendwo in die Config eintragen und neben den Rewrites und SSL-vHosts stehen lassen und dann sollte auch ein renew des Zertifikates gehen ohne das wir ein Problem haben. Der vHost muss nicht wirklich funktionieren, er muss aber erreichbar sein für CertBot.

########################
#HTTPs vHosts
########################
<virtualhost *:8181="">
	Servername <domain>.<tld>
</virtualhost>

11) ReverseProxy vHost – Vollständige Datei

Für alle, die sich oben manchmal verwirrt fühlten, wie die vollständige Datei aussehen würde, hier einmal vollständig.

########################
# CertBot Configs for all!
########################
# Setze einen Alis
Alias /.well-known/acme-challenge/ "/letsencrypt/data/.well-known/acme-challenge/"
# bestimme das Verzeichnes
<directory "="" letsencrypt="" data="" .well-known="" acme-challenge="">
    # erlaube jeder IP das Verzeichnis anzusprechen
    Require all granted
    # Der Server hält für das Verzeichnis einen Index vor und ist in der Lage Symbolische Links im Dateipfad zu verfolgen
    Options -Indexes -FollowSymLinks
    # .htaccess dateien in denen andere Einstellungen für Directories vorhanden sein können werden durch das "none" ignoriert"
    AllowOverride None
</directory>
########################
#HTTP rewrites
########################
#Einschalten der Engine
RewriteEngine on
#Bedingung: Wende Rewrites erst an, wenn die angeforderte Datei eine gültige ist!
RewriteCond %{REQUEST_FILENAME} !-f
# Wenn jetzt bei einer gültigen Datei im Pfad "well-known" auftaucht, mache nichts und beende alle weiteren Rewrites!
RewriteRule ^\.well-known/.+ - [END]
# Wenn kein "well-known" vorkahm, schreibe alles auf HTTPs um
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
######## SSL CONFIGS
# schalte die SSL-Enginge an
SSLUseStapling on
# Setze den OCSP-Responder-Timeout auf 5 sekunden
SSLStaplingResponderTimeout 5
# Sende der CA keine Responder-Errors
SSLStaplingReturnResponderErrors off
# Cache die OCSP-Responses mittels shmbc im Pfad ...
SSLStaplingCache shmcb:/var/run/ocsp(128000)
# Nehme die Apache-Standard Methode um Private-Keys beim Serverstart zu entschlüsseln
SSLPassPhraseDialog  builtin
# definiere den Ort wo SSL-Caches abgelegt sind
SSLSessionCache "shmcb:/opt/bitnami/apache/logs/ssl_scache(512000)"
# Entferne SSL-Caches nach 300 Sekunden wenn diese ungenutzt sind
SSLSessionCacheTimeout  300
########################
#HTTPs vHosts
########################
<virtualhost *:8181="">
	Servername lendel.cloud
</virtualhost>
<virtualhost *:8443="">
	# Das ist der Name des vHosts welcher gleich der Domain oder Subdomain sein sollte
	Servername lendel.cloud
	
	# hier wird die SSL-Enginge für den vHost aktiviert
	SSLEngine on
	
	# Das ist die aktivierung vom sog. HSTS
	Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
	
	# definiert welche Protokolle wir für HTTPs zulassen
	SSLProtocol             all -TLSv1 -TLSv1.1 -SSLv2 -SSLv3
	
	# definiert die genutzten Verschlüsselungsalgorithmen
	SSLCipherSuite          'kEECDH+ECDSA kEECDH kEDH HIGH +SHA !aNULL !eNULL !LOW !MEDIUM !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !RC4'
	
	# definiert das die Verschlüsselungsalgorithem in der oben genannten Reihenfolge angewendet werden, von links nach rechts
	SSLHonorCipherOrder     on
	
	# deaktiviert die komprimierung von SSL Traffic
	SSLCompression          off
	
	# sorgt dafür das jede Sitzung ein Ticket bekommt
	SSLSessionTickets       off
	
	# Pfadangabe zum Zertifikat
	SSLCertificateFile      /letsencrypt/live/lendel.cloud/cert.pem
	
	# Pfadangabe zum Privateky
	SSLCertificateKeyFile   /letsencrypt/live/lendel.cloud/privkey.pem
	
	# Pfadangabge zur Zertifikatskette
	SSLCertificateChainFile /letsencrypt/live/lendel.cloud/chain.pem
	# quasi standarad zur bestimmung des originalen protokols
	RequestHeader 	append 	"X-Forwarded-Proto" "https"
	
	# zusätzliche Information das ursprünglich SSL in der Verbindung war
	RequestHeader 	set 	"X-Forwarded-Ssl" "on"
	<location "="">
		ProxyPass        http://xxx.xxx.xxx.xxx:8080/
		ProxyPassReverse http://xxx.xxx.xxx.xxx:8080/
	</location>
</virtualhost>

11) Automation der Zertifikatserneuerung

Wir können jetzt noch die Erneuerung des Zertifikats, was alle 90 Tage ansteht, automatisieren, sodass wir das nicht machen müssen. Leider habe ich dazu nur die Option bis jetzt ermittelt, es über Crontab zu machen, was eigentlich ein Teil des NAS in dem Fall ist und nicht Teil des Containers, womit wir ein wenig „Portabilität“ verlieren, aber so ist das hier erstmal.

Wichtig hierbei ist, dass wir den Befehl als absoluten Pfad aufrufen. Dazu finden wir heraus wo unser docker installiert ist mit:

which docker

Das gibt euch jetzt einen Pfad der evtl. so aussieht:

/share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker

Sollte der Pfad bei euch von meinem abweichen, dann müsst ihr gleich im weitern Codeteil euren Pfad anpassen.

Weil Qnap scheinbar eine recht eigene Art hat Crontabs zu verwalten müssen wir wie folgt vorgehen, damit unser Crontab nach einem Neustart nicht gelöscht wird.

vi /etc/config/crontab

Jetzt solltet ihr mit VI im Ansichtsmodus eurer Crontab-Datei sein. Jetzt drückt ihr „Einfg“ auf eurer Tastatur und navigiert nach unten in die letzte Zeile und fügt ggf. eine Hinzu. Dort fügt ihr ein.

0 23 * * * /share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker run -t --rm -v /share/Container/letsencrypt/log:/var/log/letsencrypt -v /share/Container/letsencrypt:/etc/letsencrypt -v /share/Container/letsencrypt/data:/data/letsencrypt certbot/certbot renew --webroot --quiet"

Jetzt die Erklärung: Die ersten 5 Zeichen bestimmen die genaue Zeit wann der nachfolgende Befehl auszuführen ist. Das erste Zeichen ist die Minute, dann die Stunde, der Tag, Monat und dann der Wochentag wann der Befehl auszuführen ist. Im Beispiel oben heißt das, dass wir es zur Minute 0 in der Stunde 23 an jedem Tag im Monat und in der Woche ausführen. Also schlichtweg täglich um 23:00 Uhr. Der Befehl den wir ausführen ist natürlich sehr stark an den Befehl zuvor angelehnt nur das wir am Ende ein „renew“ machen im Webroot und Quiet Mode. VORSICHT: Ich hab hier erstmal den Parameter „–dry-run“ schon entfernt!

Damit jetzt die veränderte Crontab Datei geladen wird müsst ihr diese bewusst laden lassn und dann den Dienst neustarten.

crontab /etc/config/crontab && /etc/init.d/crond.sh restart

Wenn ihr überprüfen wollt ob es gelaufen ist, sollte eine Log-Datei abends um 23 Uhr täglich im Ordner /share/Container/LetsEncrypt/Log auftauchen.

12) Fazit

Wir haben einen vHost gebaut, der jetzt per CertBot über Port 80 aus dem Internet erreichbar ist. Wenn ein Browser zugreift, wird dieser immer auf HTTPS (Port 443) umgeleitet und kann nicht ungesichert mit unserer Website kommunizieren. Zudem haben wir gängige SSL-Parameter eingebaut, die das Protokoll ausreichend sicher machen und wir haben den Erneuerungsprozess des Zertifikats automatisiert. Demnach haben wir vorerst keine Arbeit! Außer wir bauen uns jetzt noch mehr vHosts hinzu, für weitere Dienste die wir haben wollen.

13) Ausblick

Weitere Services sind genau das was wir wollen. Wir haben bis hier her schonmal unsere Kontakte und Kalender auf unserem NAS zentralisiert und hiermit das alles auch beispielhaft mit HTTPs abgesichert. Jetzt schauen wir uns an wie wir KeePass als Passwortsafe ebenfalls über unser NAS im Internet sicher bereitstellen können um unsere Passwörter überall dabei zu haben!

Share this Post

Hinterlasse einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*
*