Ordnung im Königreich
Bild: Thorsten Hübner
Die Grundausstattung für öffentliche Server – automatisiert mit Ansible
Mit einem eigenen Server gewinnen Sie die Datenhoheit zurück. Bevor Sie praktische Dienste installieren können, brauchen Sie aber Zertifikate, einen Reverse-Proxy, automatische Updates und ein Admin-Interface. Mit unserem Server-Baukasten „Telerec’t“ setzen Sie das alles weitgehend automatisch mithilfe von Ansible auf.
Einen Befehl auf der Kommandozeile ausführen, zurücklehnen und zuschauen, wie die eigenen Wünsche umgesetzt werden. Wer seinen Server mit Ansible administriert, kann sich wie ein König fühlen. Wie Sie die ersten Schlachten für die Eroberung Ihres Admin-Reichs schlagen, haben wir in [1] erklärt. Nun gilt es den Server gegen Angriffe abzusichern und einige Helfer für die Verwaltung einzusetzen. Als Monarch lassen Sie nämlich arbeiten und legen nur fest, was Ihre Untertanen zu tun haben.
Den Weg zur Macht beschreiten Sie auf Ihrem Server mit „Teile und Herrsche“. Die Technik dazu heißt „Container“ [2]. Ein Container ist eine auf das Wesentliche zusammengestutzte Linux-Umgebung, die nur einen Dienst ausführt, den aber mit größter Verlässlichkeit. Docker kümmert sich um diese Mini-Linuxe und vernetzt sie virtuell zu einem föderalen Staat. Das ist deutlich effizienter als Virtualisierung, weil alle Container den Kernel des Host mitbenutzen. Der größte Vorteil liegt aber darin, dass Ihr Reich auf den Schultern von Giganten steht: Andere Herrscher teilen bereits optimierte Container-Images über Container-Registries wie den Docker Hub und Sie profitieren von deren Updates.

Regierungsbildung
Damit Ihre Container keinen Staub ansetzen, sollte Ihr Ansible-Reich „Watchtower“ benutzen, das selbst im Container läuft. Es hält Ausschau nach veralteten Docker-Images und ersetzt sie automatisch durch neuere. Dazu gesellt sich „Autoheal“, das regelmäßig prüft, ob alle Container ihre Arbeit verrichten. Wenn nicht, hilft Autoheal ihnen wieder auf die Beine.
Als Außenminister empfehlen wir den Reverse-Proxy „Træfik“ (im Folgenden Traefik geschrieben), der verlässlich alle Anfragen befreundeter Rechner annimmt und an die Container weiterleitet, die dafür zuständig sind. Traefik regelt auch die Transportverschlüsselung der Kommunikation, indem es SSL-Zertifikate von Let’s Encrypt beschafft und automatisch vor Ablauf verlängert.
Vielleicht befürchten Sie, dass es unübersichtlich werden könnte, die vielen Container gleichzeitig im Auge zu behalten. Zum Glück schafft „Portainer“ mit seinem Dashboard Abhilfe. Die Webanwendung listet all Ihre Container auf, erleichtert deren Konfiguration und hilft mit Logs bei der Fehlersuche. Also keine Sorge, dass Sie zu diesem Zweck Ihr Reich zu Fuß bereisen oder mit Konsolenbefehlen hantieren müssten.
Das Repository als Verfassung
Ansible steht Ihnen stets als Protokollchef zur Seite, der den Kleinkram für Sie verwaltet. Wir gehen im Folgenden davon aus, dass Sie Ansible installiert und ein Repository für Ihr Setup angelegt haben. Falls Sie das schnell nachholen wollen, finden Sie alle Infos in [1]. Ein Ansible-Setup besteht immer aus drei Bereichen: Variablen, Roles und Playbooks.
Mit den Variablen legen Sie all die Werte fest, die für Ihr Setup individuell sind. Das sind Benutzernamen, Passwörter, Pfade und Abweichungen von der Standardkonfiguration. Falls eine Variable nur einen bestimmten Server betrifft, legen Sie diese im Ordner host_vars/ in einer YAML-Datei fest, deren Name dem Hostnamen oder der IP-Adresse des Servers entspricht. In unserem in [1] beschriebenen Basis-Setup haben wir so unter anderem den Namen des Standardbenutzers und die Zeitzone des Servers in host_vars/192.168.7.140.yml festgelegt.
Gelten Einstellungen für mehrere Server, sind sie in group_vars/all.yml besser aufgehoben. Dort haben wir Abschnitte für jeden unserer Serverdienste erstellt und dort beispielsweise alle Benutzernamen und Passwörter festgelegt. Da unser Basis-Repository privat ist, können wir damit Passwörter über mehrere Rechner, von denen wir den Server administrieren, synchron halten, beispielsweise der Desktop-PC im Büro und das private Notebook. Falls Ihnen das zu unsicher ist, müssen Sie die Passwortverwaltung in eigene Dienste auslagern. Damit dieser Artikel nicht zu lang wird, haben wir uns gegen diesen Weg entschieden und riskiert, dass GitHub unsere Passwörter kennt.
In unserem Vorlagen-Repository github.com/ct-Open-Source/telerec-t-base enthält die Datei schon Blöcke mit den Variablen der vier Container, die Sie immer brauchen. Die Passwörter müssen Sie aber unbedingt ändern! Der folgende Linux-Befehl erzeugt ein Passwort mit 25 Zeichen und nutzt dafür die besten Zufallszahlen, die der Kernel erzeugen kann:
cat /dev/urandom | tr -dc a-zA-Z0-9 | head -c25; echo
Nutzen Sie diesen Befehl, um ein admin_password für portainer, ein http_token für watchtower und ein admin-Passwort für traefik zu erzeugen. Letzteres müssen Sie für die HTTP-Basic-Authentifizierung des Webinterfaces von Traefik noch hashen und mit dem Nutzernamen kombinieren. Der folgende Befehl macht das beispielhaft für den Benutzernamen admin und das Passwort Geheimnis:
htpasswd -nb admin Geheimnis | sed -e s/\\$/\\$\\$/g
Die Ausgabe dieses Befehls fügen Sie als Variable http_basic_users im Block traefik ein.
Sie können auch Ihren Passwortmanager benutzen, um sichere Passwörter für den Server zu erzeugen. Unter Windows und macOS würden wir von vornherein einen Passwortmanager wie KeePass [2] oder Bitwarden [3] zum Erzeugen der Passwörter empfehlen (beide laufen ebenfalls unter Linux). Da Sie die meisten Passwörter nie eingeben müssen, können Sie die extrem lang erzeugen lassen. Ausnahme: Das Passwort für BasicAuth brauchen Sie für jeden Login am Traefik-Dashboard.
Mit den Roles konfigurieren Sie, welche Dienste zu Ihrem Setup gehören. Dazu können Sie sich an unseren Vorlagen bedienen und Sub-Repositories in den Ordner roles/ klonen. Das geht mit git submodule add – ein vollständiges Beispiel hatten wir in [1] angegeben. Alternativ können Sie auch ohne Sub-Repository einfach Ordner in roles/ anlegen und selbst neue Dienste konfigurieren.
Die letzte Zutat sind Playbooks, die Sie im Wurzelverzeichnis Ihres Repository anlegen. Sie sind so kurz, dass es sich nicht lohnt, sie gesondert zu synchronisieren. Hier ein Beispiel für ein Playbook, das die Role für Traefik ausführt:
- hosts: server
become: true
roles:
- role: traefik
vars:
service_cfg: "{{ traefik }}"
Die ersten drei Zeilen sind immer gleich. Danach kommt die YAML-Liste aller Roles, die das Playbook ausführt. Die Angabe hinter vars: setzt die Variablen aus dem traefik-Block definiert in group_vars/all.yml. Die Zeile weist der Variable service_cfg den Inhalt des Blocks zu und die Compose Hull ergänzt danach diesen Block. Wir nutzen solche nahezu identischen Playbooks mit genau einer Role, um Dienste bei Bedarf einzeln neu starten zu können, beispielsweise nachdem wir eine Variable geändert haben. Ein Playbook, das gleich mehrere Dienste aufsetzt, sähe genauso aus mit einer Liste mit mehr Spiegelstrichen hinter roles:.
„Aufsetzen“ und „Neustarten“ nutzen wir bei Ansible übrigens synonym. Ansible-Playbooks dienen nämlich immer dazu, einen bestimmten Zustand auf dem Server herzustellen. War ein Dienst dort nicht installiert, müssen die im Playbook definierten Roles alle Dateien und Ordner anlegen und den Dienst starten. Lief der Dienst bereits mit einer minimalen Änderung an der Konfiguration, überprüft Ansible nur, dass die Ordner und Dateien existieren und startet mit der geänderten Konfiguration neu. Wenn Sie selbst Roles schreiben, müssen Sie daran denken, dass die auch genauso funktionieren und nicht jeder zusätzliche Durchlauf einen bereits korrekten Zustand auf dem Server noch mal verändert.
Ausführung gefällig?
Unsere Erklärung der Basisdienste kommt ohne Installationsbefehle aus, weil wir alle vier Dienste bereits als Submodules im Basis-Repository definiert haben. Zur Erinnerung: Im ersten Teil des Artikels haben Sie die Submodules mit folgendem Befehl auf den Rechner geholt:
git submodule update --init \ --recursive
Danach gibt es die Unterverzeichnisse in roles/ und Sie können die Roles in Playbooks benutzen. Die Playbooks für die vier Basisdienste haben wir im Basis-Repository schon vorbereitet und Sie können die vier Dienste nacheinander hochfahren:
pipenv run ansible-playbook traefik.yml -i hosts pipenv run ansible-playbook watchtower.yml -i hosts pipenv run ansible-playbook autoheal.yml -i hosts pipenv run ansible-playbook portainer.yml -i hosts
All das geht alternativ auch in einem einzigen Befehl:
pipenv run ansible-playbook server-setup.yml -i hosts --ask-pass --ask-become-pass
Ihr Reich hat jetzt eine einwandfreie Infrastruktur. Sie dient allerdings bislang nur dem Zweck, sich selbst zu betreiben. Mit dieser Basis können Sie nun jedoch mit gutem Gewissen die Dienste installieren, für die Sie den Server eigentlich haben wollten. Nützlich finden wir beispielsweise: Nextcloud für Dateisynchronisation, Wordpress für einen privaten Blog, Vaultwarden für die Passwortverwaltung, NodeRed und Mosquitto für das Smart Home oder Wekan für private Kanban-Boards. Wenn wir in den folgenden Ausgaben solche Dienste mit Ansible aufsetzen, verweisen wir immer auf diesen Artikel, weil die Basis immer gleich ist, egal für welche dieser Dienste Sie sich entscheiden.
Unsere Hoffnung ist, dass unser Beispiel-Setup Telerec’t Ihnen nicht nur Arbeit bei der Server-Administration abnimmt, sondern Sie auch Lust bekommen, das Setup mit eigenen Roles als Submodule zu erweitern. Von Ihren öffentlichen Repositories können dann auch andere profitieren und das Baukastensystem wächst und gedeiht. Wir verlinken Ihre Submodule-Repositories gern in der Readme-Datei unseres Basis-Repository. Schreiben Sie uns einfach eine kurze Nachricht mit dem Link an pmk@ct.de. (pmk@ct.de)
Repositories: ct.de/yruq