Bisher können unsere Domain und Subdomain nur über das unverschlüsselte HTTP Protokoll aufgerufen werden. Das ist überhaupt nicht zeitgemäß und schon gar nicht sicher. Suchmaschinen beispielsweise, schlagen äußerst ungern Seiten vor, die keine sichere TLS Verbindung anbieten.
TLS steht für Transport Layer Security und ist der Nachfolger von SSL (Secure Sockets Layer). Obwohl SSL als veraltetes Sicherheitsprotokoll gilt, hält sich die Bezeichnung hartnäckig. Wenn also mit SSL geworben wird, ist eigentlich der neue Standard TLS gemeint.
TLS Zertifikate können kostenlos und kostenpflichtig erstellt, beziehungsweise erworben werden:
Eine Zertifizierungsstelle, auch Certification Authority (CA) genannt, unterzieht sich strengen Audits, bei denen insbesondere Sicherheitskonzepte und technische Infrastruktur geprüft wird. Trotz allem, ist es eine freie Entscheidung der Software Hersteller, eine Zertifizierungsstelle als vertrauenswürdig anzuerkennen oder nicht.
Selbsterstellte Zertifikate gelten allgemein als nicht vertrauenswürdig, da ihre Echtheit von einer unabhängigen Organisation nicht bestätigt ist. Es gibt jedoch auch freie Zertifizierungsstellen, wie zum Beispiel Let's Encrypt, die Zertifikate kostenlos ausstellen.
Zertifizierungsstellen geben SSL Zertifikate nur für Domains heraus, nicht für IP Adressen.
Um Zertifikate von freien Zertifizierungsstellen beziehen zu können, gibt es Voraussetzungen, die wir mit unserem Cloud Server und der Domain erfüllen:
root Zugriff auf dem Server
einen qualifizierten Domainnamen, der über DNS abgefragt werden kann
eine Webseite die bereits online und über Port 80 erreichbar ist
In diesem Kapitel werden wir vertrauenswürdige Zertifikate für unsere Domain und Subdomain von Let's Encrypt beziehen. Außerdem erstellen wir ein selbstsigniertes Zertifikat für unsere Server IP. Die Gültigkeitsdauer von Zertifikaten ist zeitlich begrenzt, daher wird ein Automatismus benötigt, der die Zertifikate frühzeitig vor Ablauf erneuert. Das Thema Cronjobs hatten wir bereits bei Logrotate besprochen.
SSL und TLS überprüfen
Zwischenzeitlich lassen wir über den online Dienst SSL Labs unsere Konfiguration und den Status der Verschlüsselung überprüfen. Aktuell ist kein Zertifikat hinterlegt, daher ist das Ergebnis für unsere Domain entsprechend negativ:
Diesen Test werden wir später wiederholen und bekommen dann hoffentlich ein "A", vielleicht sogar ein "A+" Rating.
Certbot ist eine freie ACME-Clientsoftware (Automatic Certificate Management Environment), die uns hilft Let's Encrypt Zertifikate abzurufen und zu erneuern. Die Software kann noch mehr, aber das ist der hauptsächliche Zweck für uns.
Certbot installieren:
__$ sudo apt install -y certbot
Let's Encrypt Zertifikat für die Domain
Bevor es richtig los geht, möchte ich noch einen Spoiler öffnen: Certbot kann ein gewisses Maß an Kontrolle über Nginx oder Apache gegeben werden. Erfahrungsgemäß ist das eine bequeme Lösung, bis die Komponenten nicht mehr miteinander harmonieren. Wenn vielleicht Certbot geupdatet werden muss, die Server aber wegen der laufenden Webprojekte mit einer Aktualisierung noch warten müssen. Solche Abhängigkeiten versuche ich zu vermeiden, was meistens bedeutet, dass bei der Implementation ein Mehraufwand entsteht. Ich setze Certbot so ein, dass es Zertifikate beantragt und sie automatisch erneuert. Mehr soll es nicht tun. Die Konfiguration der Server Dienste möchte ich selbst kontrollieren.
Grundsätzlich muss für den Zertifikatsantrag die Domain oder Subdomain öffentlich über den Port 80 erreichbar sein. Was wir bereits im letzten Kapitel unter Server Block für eine Domain vorbereitet haben.
Mit folgendem Befehl beantragen wir ein Zertifikat mit Certbot bei Let's Encrypt. Es soll für die Domain und die "Subdomain" www gültig sein:
Es gibt noch einen kompakteren Befehl, wo die webroot Methode und das Verzeichnis gleich mitangegeben werden: sudo certbot certonly --webroot -w /var/www/com.linuxserversetup -d linuxserversetup.com -d www.linuxserversetup.com --rsa-key-size 4096
Wir müssen natürlich die Inhaberschaft über die Domain nachweisen. Das erledigen wir mit der "webroot" Methode. Den webroot haben wir für die Domain schon angelegt: /var/www/com.linuxserversetup. Meine Eingaben zum obigen Befehl lauten:
Place files in webroot directory (webroot): 2
Enter email address: an diese Adresse gehen Bestätigungen, Fehlerberichte und Ankündigungen seitens Let's Encrypt
Please read the Terms of Service: a
Newsletter: n
Input the webroot for linuxserversetup.com: /var/www/com.linuxserversetup
Select the webroot for www.linuxserversetup.com: 2
Saving debug log to /var/log/letsencrypt/letsencrypt.log
How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Plugins selected: Authenticator webroot, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): tom@linuxservrsetup.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: a
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: n
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for linuxserversetup.com
http-01 challenge for www.linuxserversetup.com
Input the webroot for linuxserversetup.com: (Enter 'c' to cancel): /var/www/com.linuxserversetup
Select the webroot for www.linuxserversetup.com:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Enter a new webroot
2: /var/www/com.linuxserversetup
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/linuxserversetup.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/linuxserversetup.com/privkey.pem
Your cert will expire on 2022-02-23. 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
In der Antwort steht der Ort, wo die Zertifikate abgelegt wurden. Genauer gesagt, liegen dort Verknüpfungen zu den tatsächlichen Dateien:
__$ sudo ls -la /etc/letsencrypt/live/linuxserversetup.com/
Die Zertifikate sind drei Monate gültig und werden automatisch innerhalb des letzten Monats erneuert. Der Cronjob dazu wurde hier angelegt:
__$ sudo nano /etc/cron.d/certbot
Ausgabe:
/etc/cron.d/certbot
# /etc/cron.d/certbot: crontab entries for the certbot package
#
# Upstream recommends attempting renewal twice a day
#
# Eventually, this will be an opportunity to validate certificates
# haven't been revoked, etc. Renewal will only occur if expiration
# is within 30 days.
#
# Important Note! This cronjob will NOT be executed if you are
# running systemd as your init system. If you are running systemd,
# the cronjob.timer function takes precedence over this cronjob. For
# more details, see the systemd.timer manpage, or use systemctl show
# certbot.timer.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew
Auf unserem Ubuntu Linux ist es eher unwahrscheinlich, dass dieser Crontab berücksichtigt wird, da hier für gewöhnlich ein systemd timer die zeitliche Prozesssteuerung kontrolliert. Daher hat Certbot einen /lib/systemd/system/certbot.timer angelegt, der alle 12 Stunden die Ausführung von /lib/systemd/system/certbot.service auslöst.
Um nun herauszufinden, ob systemd die Kontrolle auf dem System hat, reicht es die Existenz von /run/systemd/system/ zu überprüfen:
__$ ls /run/systemd/system/
Über die Ausgabe durch systemctl list-timers, sollte der Certbot Timer aufgeführt sein:
__$ systemctl list-timers
Ausgabe:
NEXT LEFT LAST PASSED UNIT ACTIVATES
...
Wed 2022-01-05 16:40:04 UTC 29min left Wed 2022-01-05 02:55:54 UTC 13h ago certbot.timer certbot.service
...
Dort sehen wir, dass der Befehl /usr/bin/certbot -q renew die Zertifikate erneuert.
Nachdem ein Zertifikat erneuert wurde, muss Nginx neugeladen werden. Für diese Aufgabe eignet sich der Certbot Parameter --deploy-hook. Eine schlechte Lösung wäre, das über den certbot.service zu erledigen. Die vollständige Datei mit der geänderten ExecStart Zeile würde dann so aussehen:
# renew_before_expiry = 30 days
version = 0.40.0
archive_dir = /etc/letsencrypt/archive/linuxserversetup.com
cert = /etc/letsencrypt/live/linuxserversetup.com/cert.pem
privkey = /etc/letsencrypt/live/linuxserversetup.com/privkey.pem
chain = /etc/letsencrypt/live/linuxserversetup.com/chain.pem
fullchain = /etc/letsencrypt/live/linuxserversetup.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
account = adg4c513fhe12318sfvb76fd387
rsa_key_size = 4096
authenticator = webroot
server = https://acme-v02.api.letsencrypt.org/directory
[[webroot_map]]
linuxserversetup.com = /var/www/com.linuxserversetup
www.linuxserversetup.com = /var/www/com.linuxserversetup
Hier ergänzen wir renew_hook = service nginx reload. Die Datei können wir wie gehabt mit dem Editor nano bearbeiten oder mit diesem Einzeiler. Mit sed suchen wir die Zeile [renewalparams] und ergänzen darunter den renew_hook Teil:
__$ sudo sed -i '/\[renewalparams]/arenew_hook = service nginx reload' /etc/letsencrypt/renewal/linuxserversetup.com.conf
# renew_before_expiry = 30 days
version = 0.40.0
archive_dir = /etc/letsencrypt/archive/linuxserversetup.com
cert = /etc/letsencrypt/live/linuxserversetup.com/cert.pem
privkey = /etc/letsencrypt/live/linuxserversetup.com/privkey.pem
chain = /etc/letsencrypt/live/linuxserversetup.com/chain.pem
fullchain = /etc/letsencrypt/live/linuxserversetup.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
account = adg4c513fhe12318sfvb76fd387
rsa_key_size = 4096
authenticator = webroot
server = https://acme-v02.api.letsencrypt.org/directory
renew_hook = service nginx reload
[[webroot_map]]
linuxserversetup.com = /var/www/com.linuxserversetup
www.linuxserversetup.com = /var/www/com.linuxserversetup
Die .well-known Freigabe
Für die Autorisierung durch Let's Encrypt muss Zugriff auf eine bestimmte Adresse (http://www.linuxserversetup.com/.well-known/acme-challenge/) gegeben sein. Serverseitig wird in das webroot Verzeichnis, welches zuvor bei der Beantragung angegeben wurde, vom letsencrypt Dienst genutzt, um eine temporäre Datei unter /var/www/com.linuxserversetup.com/.well-known/acme-challenge zu erstellen. Nachdem das Zertifikat erneuert wurde, wird diese Datei auch wieder entfernt. Den .well-known/acme-challenge Pfad müssen wir selbst erstellen, wo wir gleich zu kommen. Ein Hinweis an dieser Stelle: der .well-known Ordner ist dafür berüchtigt, dass Hacker nach einem erfolgreichem Einbruch dort ihre Malware platzieren. Sie ist dort gut versteckt und kann durch die genannte Freigabe aus dem Internet abgerufen werden. Es schadet also nicht, zwischendurch mal dort reinzuschauen oder einen Automatismus zu erzeugen, der diese Ordner in gewissen Zeitabständen leert.
Zertifikate in der NGINX Konfiguration übernehmen
Die zuständige Konfigurationsdatei (/etc/nginx/sites-available/com.linuxserversetup.conf) müssen wir für HTTPS entsprechend umändern:
Nach dem speichern überprüfen wir die neue Konfiguration und starten NGINX neu:
__$ sudo nginx -t
__$ sudo systemctl reload nginx
Certbots automatische Erneuerung überprüfen
Bevor es weiter geht, können wir noch überprüfen, ob Certbot überhaupt in der Lage ist, Zertifikate zu erneuern. Dazu gibt es den Parameter --dry-run. Dieser simuliert den Prozess und erstellt anschließend ein Bericht.
__$ sudo certbot renew --dry-run
Mit SSL Labs überprüfen
Wiederholen wir den Test jetzt mit SSL Labs, sollte unsere Konfiguration mit "A" eingestuft sein:
SSL Labs: A-Rating
Das "Rating" kann noch verbessert werden, indem wir einen Diffie-Hellman Schlüssel hinzufügen. Wir erstellen einen mit OpenSSL, der Ablageort soll /etc/ssl/certs/ sein:
Achtung Spoiler: Die Berechnung wird auf unserem CPX11 mindestens 10 Minuten dauern:
Generating DH parameters, 4096 bit long safe prime, generator 2
This is going to take a long time
...............................................+..................................
..................................................................................
...................................................................+..............
..................................................................................
..................................................................................
Indem wir HSTS aktivieren, ist sogar ein "A+" Rating möglich. Durch HSTS wird der HTTP Header Strict-Transport-Security übertragen, was dem Browser mitteilt, dass diese Adresse nur über HTTPS aufgerufen werden soll. Der mitgelieferte Wert, ist der Zeitraum in Sekunden, für die der Browser sich das merken soll. Für gewöhnlich ein Jahr (31536000 Sekunden).
Den Pfad zum PEM Zertifikat und den HSTS Header geben wir wie zuvor in die NGINX Site-Konfiguration ein:
Zuletzt geben wir für eine Verbindung auch die erlaubten Verschlüsselungsverfahren (Cipher) mit ssl_ciphers vor, die ein Browser unterstützen muss. Hier gilt ein gutes Maß zwischen Sicherheit und aussreichend Browserkompatibilität zu finden:
Die Seite ssl-config.mozilla.org kann helfen, um weitere Einstellungen vorzunehmen. Es ist aber zu beachten, dass noch eine gewisse Abwärtskompatibilität vorhanden sein sollte. Denn eine zu strenge TLS Konfiguration wird ältere Geräte ausschließen.
Selbstsigniertes TLS Zertifikat für den Default Server Block
Let's Encrypt stellt TLS Zertifikate nur für qualifizierte Domainnamen aus. Daher müssen wir für unsere IP ein selbstsigniertes Zertifikat hinterlegen. Für gewöhnlich ist es gar nicht erwünscht, dass jemand die Server IP direkt im Browser abruft. Da es aber möglich ist, sollte dieser Austausch auch verschlüsselt sein. An der Stelle ist es auch nicht wichtig, ob das Zertifikat vertrauenswürdig ist. Es tut was es soll, nämlich verschlüsseln. Und wem das zu unsicher ist, soll die IP nicht zu besuchen.
Mit dem folgenden OpenSSL Befehl erstellen wir ein Zertifikat und einen Schlüssel mit dem RSA Verschlüsselungsverfahren. Die Komplexität soll 2048 Bit betragen mit einer Gültigkeitsdauer von 365 Tagen:
Während der Prozedur bestätige ich Country Name mit DE und Common Name mit der Server IP 116.203.69.89. Zu dem Rest kannst Du Angaben machen oder einfach durch Entern.
gned.key -out /etc/ssl/certs/nginx-selfsigned.crt
Generating a RSA private key
.................................................+++++
......+++++
writing new private key to '/etc/ssl/private/nginx-selfsigned.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:116.203.68.89
Email Address []:
Die erzeugten Dateien sind:
/etc/ssl/private/nginx-selfsigned.key
/etc/ssl/certs/nginx-selfsigned.crt
__$ sudo ls -la /etc/ssl/private/
__$ sudo ls -la /etc/ssl/certs/
Die müssen wir jetzt nur noch in der obigen default Konfiguration hinterlegen.
Öffnen wir die Datei zum Bearbeiten:
__$ sudo nano /etc/nginx/sites-available/default
Wir werden einen weiteren Server Block am Anfang der Datei hinzufügen. Dieser leitet von HTTP auf HTTPS um und erzwingt damit eine verschlüsselte Übertagung. Der Zweite ursprüngliche Block wird um die beiden Pfade ergänzt, die zu dem selbstsignierten Schlüssel (ssl_certificate) und dem Zertifikat (ssl_certificate_key) führen.
Wenn wir schon dabei sind, können wir auch den oben erzeugten Diffie-Hellman Schlüssel mit angeben.
Die vollständige Datei sollte folgenden Inhalt haben:
Überprüfen wir die neue Konfiguration und starten NGINX neu:
__$ sudo nginx -t
__$ sudo systemctl reload nginx
Der Aufruf von http://116.203.69.89 leitet jetzt nach https://116.203.69.89 um. Es ist also gar nicht mehr möglich Daten unverschlüsselt zu übertragen.
Let's Encrypt Zertifikat für die Subdomain
Im Grunde wiederholt sich der erste Abschnitt, wo wir ein Zertifikat für die Domain eingerichtet haben. Daher die Schritte jetzt für die Domain im Schnelldurchgang.
Die Subdomain muss über Port 80 erreichbar sein, was wir bereits im letzten Kapitel unter Server Block für eine Subdomain vorbereitet haben.
Der Vollständigkeit halber wird hier beschrieben, wie eine Domain aus dem Certbot-Prozess ausgeschlossen und die entsprechenden Certbot-Dateien entfernen werden.
Führen den Befehl certbot delete aus und wähle die zu löschende Domain:
__$ sudo certbot delete
Certbot zeigt eine nummerierte Liste an und erwartet die Eingabe einer Zahl:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Which certificate(s) would you like to delete?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: linuxserversetup.com
2: dev.linuxserversetup.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):
Nach der Eingabe der entsprechenden Nummer wird eine Meldung angezeigt, dass die Domain von Certbot gelöscht wurde: