Ubuntu Server 14.04 – SSL-Zertifikate mit Let's Encrypt

Zur gesicherten Übertragung von Webseiten mit dem „HyperText Transfer Protocol Secure“ HTTPS werden SSL(„Secure Sockets Layer“)- bzw. TLS(„Transport Layer Security“)-Zertifikate benötigt. Diese werden von vertrauenswürdigen Zertifizierungsstellen ausgegeben und sind überwiegend kostenpflichtig. Seit Ende 2015 gibt es mit Let’s Encrypt eine interessante Alternative zu kommerziellen Anbietern.
Nachfolgend werden wir Let’s Encrypt für die Generierung von Zertifikaten auf einem Ubuntu-Server-14.04-System einrichten und eine HTTPS-Musterkonfiguration für den Webserver Apache anlegen. Um die Zertifikatsverwaltung zu erleichtern, erstellen wir ein Skript zur automatischen Zertifikatserneuerung. Abschließend behandeln wir die Aktualisierung und die Deinstallation des Let’s-Encrypt-Clients.
Die Anleitung bezieht sich auf Let’s Encrypt in der Beta-Phase Stand Januar 2016. Weitere Einzelheiten und aktuelle Änderungen enthält die Original-Dokumentation.

Voraussetzungen

Wir haben unseren Server z. B. gemäß den Anleitungen zur Ubuntu-Server-Basisinstallation und zur LAMP-Server-Installation konfiguriert und durch Updates / Upgrades auf den neuesten Stand gebracht. Die Befehle führen wir mit Root-Rechten aus, z. B. nach Öffnen einer Rootshell mit sudo -i.

Let’s Encrypt installieren

Let’s Encrypt verwaltet Zertifikate mit Hilfe eines speziellen ACME(„Automatic Certificate Management Environment“)-Clients. Unter Ubuntu Server 14.04 kann der Let’s-Encrypt-Client (noch) nicht mit der Paketverwaltung APT („Advanced Packaging Tool“) installiert werden. Stattdessen benötigen wir die Versionsverwaltung Git:

root@server:~# apt install git

Mit git clone kopieren wir die Paketquellen in das (frei wählbare) Verzeichnis /root/sources/letsencrypt, das während des Vorgangs – falls noch nicht vorhanden – automatisch angelegt wird:

root@server:~# git clone https://github.com/letsencrypt/letsencrypt /root/sources/letsencrypt

Die Installation wird beim erstmaligen Aufruf des Let’s-Encrypt-Clients mit letsencrypt-auto gestartet. Mit der Option ‐‐help können wir uns hierbei gleich einen ersten Überblick über die Aufrufparameter verschaffen:

root@server:~# /root/sources/letsencrypt/letsencrypt-auto --help

Während des Installationsvorgangs erscheinen folgende Warnmeldungen:

...
Updating letsencrypt and virtual environment dependencies...../root/.local/share/letsencrypt/local/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
/root/.local/share/letsencrypt/local/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
.
...

Grund ist, dass bei Ubuntu Server 14.04 mit APT als aktuellste Python-Version nur 2.7.6 installiert wird, letsencrypt-auto aber Version 2.7.9 oder höher erwartet. Die obigen Meldungen traten bei dem für diesen Artikel verwendeten Testsystem allerdings nur beim ersten Start von Let’s Encrypt auf und können daher vermutlich ignoriert werden.

SSL-Zertifikat erstellen

Zum Beantragen eines SSL-Zertifikats und zur automatischen Installation der zugehörigen Schlüssel- und Zertifikatsdateien auf unserem Server rufen wir letsencrypt-auto mit dem Parameter certonly und der Option standalone auf. Vorab müssen wir den Webserver Apache anhalten und danach wieder starten, da der Let’s-Encrypt-Client zur Validierung der Domain den Port 80 nutzt:

root@server:~# service apache2 stop
root@server:~# /root/sources/letsencrypt/letsencrypt-auto certonly --standalone --agree-tos --email webmaster@test.local --domain www.test.local --rsa-key-size 4096
root@server:~# service apache2 start

Mit der Option agree-tos stimmen wir den Nutzungsbedingungen zu. An die per email übergebene E-Mail-Adresse werden z. B. Benachrichtigungen zu anstehenden Zertifikatserneuerungen geschickt. Diese beiden Optionen müssen nur beim ersten Aufruf angegeben werden.
Der verwendete Domainname www.test.local und die E-Mail-Adresse webmaster@test.local sind Platzhalter, die wir durch die realen Daten unseres eigenen Servers ersetzen. Zertifikatsanfragen für nicht öffentlich zugängliche Domains wie test.local werden von Let’s Encrypt (sinnvollerweise) abgewiesen.
Die Option rsa-key-size 4096 erhöht die Schlüssellänge des privaten Schlüssels von den voreingestellten 2048 bit auf sicherere 4096 bit.
Da wir alle Optionen direkt beim Aufruf von letsencrypt-auto certonly übergeben, erhalten wir nicht die ansonsten angezeigten Menüs.

Apache konfigurieren

Die von Let’s Encrypt erzeugten Schlüssel und Zertifikate werden in /etc/letsencrypt/live/www.test.local als symbolische Links auf die jeweils aktuellen Versionen hinterlegt. Die Datei privkey.pem beinhaltet den privaten Schlüssel, die Datei cert.pem das Serverzertifikat. In chain.pem werden alle Zertifikate der vom Root-Zertifikat ausgehenden Zertifikatskette mit Ausnahme des Serverzertifikats gespeichert. fullchain.pem enthält zusätzlich das Serverzertifikat.
Abhängig vom Versionsstand benötigt Apache neben der Schlüsseldatei unterschiedliche Zertifikatsdateien. Für das für diesen Artikel genutzte Testsystem mit Apache 2.4.7 lauten die entsprechenden Einträge in der Konfigurationsdatei:

...
SSLCertificateChainFile /etc/letsencrypt/live/www.test.local/chain.pem
SSLCertificateFile /etc/letsencrypt/live/www.test.local/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.test.local/privkey.pem
...

Bei neueren Versionen kommt man mit zwei Zeilen aus:

...
SSLCertificateFile /etc/letsencrypt/live/www.test.local/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.test.local/privkey.pem
...

In Anlehnung an den Artikel zur LAMP-Server-Installation sieht die komplette Definition eines virtuellen Hosts www.test.local in der HTTPS-Standardkonfigurationsdatei /etc/apache2/sites-available/default-ssl.conf dann beispielsweise folgendermaßen aus:

<VirtualHost *:443>
  CustomLog ${APACHE_LOG_DIR}/access-html-ssl.log vhost_combined
  DocumentRoot /var/www/html
  ErrorLog ${APACHE_LOG_DIR}/error-html-ssl.log
  ServerAdmin webmaster@test.local
  ServerName www.test.local
  SSLCertificateChainFile /etc/letsencrypt/live/www.test.local/chain.pem
  SSLCertificateFile /etc/letsencrypt/live/www.test.local/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/www.test.local/privkey.pem
  SSLEngine on
  <Directory /var/www/html>
    Require all granted
  </Directory>
</VirtualHost>

Schließlich aktivieren wir noch, falls nicht bereits vorher geschehen, die HTTPS-Konfiguration und starten den Webserver neu:

root@server:~# a2ensite default-ssl.conf
root@server:~# service apache2 restart

Website testen

Für einen einfachen Test unserer Website können wir sie in einem Webbrowser aufrufen. In der Adressleiste von Firefox sollte dann z. B. links neben der Adresse ein grünes Sperrschloss angezeigt werden. Mit einem Klick auf die Ausrufezeichen-Schaltfläche vor dem Schloss erhalten wir weitere Details über unser Let’s-Encrypt-Zertifikat.

Zertifikate erneuern

Die von Let’s Encrypt ausgestellten SSL-Zertifikate sind für einen Zeitraum von 90 Tagen gültig. Zur Zertifikatserneuerung ruft man den Let’s-Encrypt-Client erneut auf:

root@server:~# /root/sources/letsencrypt/letsencrypt-auto certonly --standalone --domain www.test.local --rsa-key-size 4096 --renew-by-default

Die beiden Angaben agree-tos und email können entfallen, da die zugehörigen Werte beim ersten Aufruf von letsencrypt-auto gespeichert werden. Mit der zusätzlichen Option renew-by-default wird eine Erneuerung ohne weitere Rückfragen erzwungen.
Damit nicht versehentlich Zertifikate ablaufen und ungültig werden, bietet es sich an, die manuelle Zertifikatserneuerung zeitgesteuert zu automatisieren. Dazu legen wir ein kleines Shellskript /root/letsencrypt_renew.sh an:

#!/bin/bash
if test $(find /etc/letsencrypt/live/$1 -mtime +$2 -name privkey.pem); then
  service apache2 stop;
  /root/sources/letsencrypt/letsencrypt-auto certonly --standalone --domain $1 --rsa-key-size 4096 --renew-by-default
  service apache2 start;
fi

Das Skript überprüft, ob die Schlüsseldatei privkey.pem für den als ersten Aufrufparameter übergebenen Domainnamen $1 älter als die Anzahl von Tagen im zweiten Aufrufparameter $2 ist und startet in diesem Fall die Erneuerungsanfrage.
letsencrypt_renew.sh muss für den Benutzer root ausführbar sein, daher ändern wir noch die Zugriffsrechte:

root@server:~# chmod 0700 /root/letsencrypt_renew.sh

Unter Ubuntu ermöglicht der Cron-Dienst das Ausführen von Befehlen, Skripten und Programmen zu vorgegebenen Zeitpunkten. Die zugehörigen Angaben werden dabei in sogenannten „crontab“-Dateien hinterlegt, die benutzerspezifisch angelegt werden können. Für den Benutzer root rufen wir hierzu den Befehl crontab mit der Editier-Option -e wie folgt auf:

root@server:~# crontab -e -u root

Beim ersten Start wird der Editor zur Bearbeitung abgefragt und diese Information für weitere Aufrufe gespeichert. Nach der Editor-Auswahl ergänzen wir am Ende der Datei folgende Zeile:

...
00 03 * * * /root/letsencrypt_renew.sh www.test.local 30

Hiermit weisen wir den Cron-Dienst an, täglich um 3 Uhr morgens zu prüfen, ob das Zertifikat für die Domain www.test.local älter als 30 Tage ist, um es dann gegebenenfalls zu erneuern. Wir orientieren uns hierbei an der Let’s-Encrypt-Dokumentation, die zur Vermeidung von Problemen einen Zeitraum von einem Monat zwischen zwei Erneuerungsanfragen nennt.

Let’s-Encrypt-Client aktualisieren

Bei jedem Aufruf von letsencrypt-auto wird geprüft, ob eine neuere Version des Let’s-Encrypt-Clients vorliegt und dieser dann gegebenenfalls aktualisiert. Falls keine automatische Aktualisierung gewünscht ist, kann man stattdessen das Programm letsencrypt verwenden, das dieselben Parameter und Optionen nutzt. Das Update erfolgt dann wie die ursprüngliche Installation mit Hilfe der Versionsverwaltung Git. Dazu rufen wir git pull mit dem Installationsverzeichnis /root/sources/letsencrypt als Parameter auf:

root@server:~# git -C /root/sources/letsencrypt pull

Let’s Encrypt deinstallieren

Für den unwahrscheinlichen Fall, dass wir Let’s Encrypt nicht mehr benötigen, müssen wir die Deinstallation mangels eines automatisierten Verfahrens manuell durchführen. Hierzu löschen wir das Installationsverzeichnis sowie die Ordner für die Konfiguration, die Statusinformationen, die Logdateien und die Paketquellen:

root@server:~# rm -r /root/.local/share/letsencrypt /etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt /root/sources/letsencrypt

Falls die Versionsverwaltung Git nicht von anderer Software genutzt wird, kann man sie mit apt remove ebenfalls entfernen:

root@server:~# apt remove git

Hinweise auf die von Let’s Encrypt zusätzlich installierten Programmpakete finden sich im Bootstrap-Skript /root/sources/letsencrypt/bootstrap/_deb_common.sh. Vor der Deinstallation dieser Programme sind natürlich etwaige Abhängigkeiten zu anderen Softwarepaketen zu prüfen.