Archiv des Autors: Jörg Kastning

SSH ForwardAgent ja oder nein?

In diesem Artikel möchte ich diskutieren, ob die Nutzung der SSH-Client-Option ForwardAgent sicher und sinnvoll ist. Wie so häufig bei Themen der IT-Sicherheit geht es auch hier um die Abwägung zwischen Sicherheit und Bequemlichkeit.

Der SSH-Agent nimmt den privaten SSH-Schlüssel auf und stellt diesen für SSH-Verbindungen bereit, so dass nicht bei jeder neuen SSH-Verbindung die Passphrase eingegeben werden muss.

Dabei wird ein UNIX-Socket erstellt und in der Variablen SSH_AUTH_SOCK gespeichert. Der folgende Code zeigt dies beispielhaft:

$ echo $SSH_AUTH_SOCK
/run/user/1000/keyring/ssh

In der ssh_config(5) findet sich die Option ForwardAgent, mit deren Hilfe der SSH-Agent auf einen entfernten Rechner weitergeleitet werden kann. Ist diese Funktionalität aktiv, kann man sich mit dem im SSH-Agenten gespeicherten privaten SSH-Schlüssel zu einem entfernten Rechner verbinden und von dort aus unter Nutzung des gleichen Schlüssels Verbindungen zu weiteren Rechnern aufbauen.

In den meisten Linux-Distributionen ist diese Option standardmäßig deaktiviert, da sie ein potenzielles Sicherheitsrisiko darstellt. Gelingt es einem Benutzer, die Dateiberechtigungen auf dem entfernten Rechner zu umgehen, kann er den lokalen Agenten benutzen, um Operationen durchzuführen, die nur mit dem im SSH-Agenten gespeicherten SSH-Schlüssel möglich sind. Ich möchte dies im Folgenden an einem Beispiel veranschaulichen.

Die Umgebung

Für den Versuch kommen die drei Linux-Rechner host-a, host-b und host-c zum Einsatz. Auf allen drei Hosts existiert der User foo, welcher mittels sudo zum root werden kann. Darüber hinaus existiert auf host-b User bar, welcher ebenfalls mittels sudo zum root werden darf.

Gezeigt wird, wie bar durch Wechsel in den Kontext des Users root die Dateiberechtigungen für den Unix-Socket des SSH-Agenten von foo umgehen kann, um mit dessen Informationen eine SSH-Verbindung zu host-c herzustellen, was ihm sonst nicht gestattet ist.

Der Versuchsablauf

In diesem Abschnitt wird der Ablauf wiedergegeben, der dazu führt, dass bar Zugriff als foo auf host-c bekommt.

host-a

Auf host-a existiert ein Unix-Socket für den SSH-Agenten. Der User foo nutzt diesen, um eine Verbindung zu host-b aufzubauen. Dabei wird die Option ForwardAgent aktiviert:

foo@host-a:~$ echo $SSH_AUTH_SOCK
/run/user/1000/keyring/ssh
foo@host-a:~$ ssh -o ForwardAgent=yes  host-b
[...]
foo@host-b:~$

host-b

Wir sind jetzt via SSH als User foo auf dem host-b eingeloggt. Da wir die Weiterleitung des SSH-Agenten aktiviert haben, existiert jetzt auch hier ein entsprechender Unix-Socket. Die Dateiberechtigungen sind so gesetzt, dass nur foo darauf zugreifen darf. Der folgende Codeblock veranschaulicht dies.

foo@host-b:~$ echo $SSH_AUTH_SOCK
/tmp/ssh-fxwQXNlZrS/agent.32579
foo@host-b:~$ ls -ld /tmp/ssh-fxwQXNlZrS
drwx------ 2 foo foo 4096 Nov 24 14:47 /tmp/ssh-fxwQXNlZrS
foo@host-b:~$ ls -l /tmp/ssh-fxwQXNlZrS/agent.32579
srwxr-xr-x 1 foo foo 0 Nov 24 14:47 /tmp/ssh-fxwQXNlZrS/agent.32579

Neben foo ist auch User bar auf host-b eingeloggt. Die Variable SSH_AUTH_SOCK dieses Users ist leer und bar wird beim Versuch, sich mit host-c zu verbinden, zur Eingabe eines Passworts aufgefordert.

bar@host-b:~$ echo $SSH_AUTH_SOCK

bar@host-b:~$ ssh foo@host-c
foo@host-c's password:

bar@host-b:~$ ls -l /tmp
drwx------ 2 foo   foo   4096 Nov 24 14:56 ssh-fxwQXNlZrS
bar@host-b:~$ ls -l /tmp/ssh-fxwQXNlZrS
ls: cannot open directory '/tmp/ssh-fxwQXNlZrS/': Permission denied

Da bar das Kennwort von foo unbekannt ist, geht es auf diesem Weg nicht weiter. Jedoch kann bar erkennen, dass auf dem System ein Unix-Socket mit einem SSH-Agenten für foo existiert. Der nun folgende Codeblock zeigt, wie bar über einen Umweg den SSH-Agenten von foo nutzt, um sich mit host-c zu verbinden.

bar@host-b:~$ sudo -i
[sudo] password for bar:
root@host-b:~# ssh foo@host-c
foo@host-c's password:

root@host-b:~# SSH_AUTH_SOCK=/tmp/ssh-fxwQXNlZrS/agent.32579
root@host-b:~# export SSH_AUTH_SOCK
root@host-b:~# ssh foo@host-c
[...]
foo@host-c:~$

Der User bar hat es geschafft, sich als foo an host-c zu authentifizieren. Das ist foobar!

Schlussfolgerung

Der hier durchgeführte Versuch zeigt, dass die Option ForwardAgent ein Sicherheitsrisiko birgt, wenn es auf einem entfernten System Benutzer gibt, welche die Dateiberechtigungen, wie in diesem Artikel gezeigt, umgehen können.

Ich empfinde es daher als gut und sinnvoll, dass diese Option standardmäßig deaktiviert ist.

Kann man jedoch ausschließen, dass die Dateiberechtigungen umgangen werden, z. B. weil keine weiteren Nutzer auf dem entfernten Rechner existieren bzw. auf diesen zugreifen können, spricht in meinen Augen nichts dagegen, diese Option zu nutzen und sich den Alltag etwas komfortabler zu gestalten.

Let’s Encrypt: Nutzung des DNS-Alias-Modus mit dem acme.sh-Client

Dieses Tutorial erklärt, wie der Let’s Encrypt Client (LE-Client) acme.sh mit dem Plugin dns_nsupdate auf einem Linux-System installiert und zur Nutzung der „DNS-01 challenge“ im DNS-Alias-Modus konfiguriert werden kann.

Um dem Tutorial folgen zu können, sollte man den grundlegenden Umgang mit einem Terminal und einer weitgehend POSIX-kompatiblen Shell beherrschen. Grundlegende Kenntnisse der Funktion von DNS und Resource Records sind hilfreich, jedoch nicht erforderlich und können im Zweifel unter den verlinkten Seiten erworben werden.

In diesem Tutorial werden nicht die Vor- und Nachteile der „DNS-01 challenge“ diskutiert. Diese können unter vorstehendem Link nachgelesen werden.

Die Begriffe SSL-Zertifikat, TLS-Zertifikat oder nur Zertifikat werden in diesem Tutorial synonym verwendet. Der zum Zertifikat gehörende Schlüssel wird als Private-Key bezeichnet.

Umfeld

Im Folgenden werden die Begriffe Subdomain und Zone synonym verwendet. Es sei darauf hingewiesen, dass diese Begriffe in einem anderen Kontext eine unterschiedliche Bedeutung haben können.

Als Beispiel-Domain wird example.org mit den beiden Subdomains foo.example.org und bar.example.org verwendet. Um dem acme.sh-Client keinen direkten Zugriff auf diese DNS-Zonen geben zu müssen, hat der DNS-Anbieter die DNS-Zone acme.foo.example.org definiert, welche für den Zweck der DNS-Challenge verwendet wird.

Der Nameserver für alle in diesem Tutorial verwendeten Domains lautet ns.example.org.

Vom DNS-Anbieter wird ein sogenannter TSIG-Schlüssel bereitgestellt, welcher berechtigt ist TXT-Ressource-Records in der oben genannten DNS-Zone acme.foo.example.org anlegen zu können. In diesem Tutorial werden folgender Name und Wert für einen TSIG-Schlüssel angenommen:

  • TSIG-NAME: acme-key
  • TSIG-WERT: SuperGeheim1111elf==
  • TSIG-Algorithmus: hmac-sha512

Das Ziel soll nun sein, ein Zertifikat ausgestellt zu bekommen, welches für die beiden folgenden Hostnamen gültig ist:

  • host.foo.example.org
  • mein-schoener-host.bar.example.org

In diesem Tutorial wird als Webserver Apache in der Distribution RHEL 7 verwendet. Die entsprechende Service-Unit lautet demnach httpd.service. Wird ein anderer Webserver oder eine andere Distribution verwendet, ist der Name der Service-Unit entsprechend anzupassen (z.B. nginx.service).

Sinn und Zweck des DNS-Alias-Modus

Der DNS-Alias-Modus kann verwendet werden, wenn man einem Programm wie dem acme.sh-Client keinen direkten API-Zugriff auf die DNS-Zonen der eigenen Domain geben möchte. In diesem Abschnitt werde ich beispielhaft erklären, warum eine Nutzung dieses Modus angeraten erscheint.

Bevor Let’s Encrypt ein Zertifikat ausstellt, muss der anfragende Client beweisen, dass er die administrative Kontrolle über die Domain hat. Im Falle der DNS-Challenge geschieht dies indem ein TXT-Record in der jeweiligen DNS-Zone erstellt wird. Der LE-Client benötigt somit Zugriff mit Schreibberechtigung auf die entsprechenden DNS-Zonen. Dies kann jedoch verheerende Folgen haben, wenn der Host mit dem LE-Client kompromittiert wird. Ein Angreifer könnte hierdurch API-Zugang erlangen und die Informationen einer (oder mehrere) DNS-Zonen löschen. Oder noch schlimmer, die Einträge manipulieren bzw. eigene Einträge hinzufügen.

In unserer Organisation hat daher nur autorisiertes Personal mit personalisierten Zugangsdaten Zugriff auf ausgewählte Zonen.

Eine wichtige Eigenschaft von personalisierten Zugangsdaten ist, dass diese nur von der Person verwendet werden, an die sie ausgehändigt wurden. Diese sollten tunlichst nicht in einen LE-Client eingetragen werden, den man anschließend für Monate oder Jahre sich selbst überlässt.

Der DNS-Alias-Modus funktioniert so, dass der DNS-Anbieter eine Zone einrichtet, in der dynamische Updates durch LE-Clients gestattet sind. Die Authentifizierung und Autorisierung kann mittels sogenannter TSIG-Schlüssel durchgeführt werden.

Als Sysadmin erstellt man nun einen CNAME-Eintrag in der eigentlichen DNS-Zone, z.B. foo.example.org welcher auf die Zone acme.foo.example.org zeigt. Der LE-Client legt während der DNS-Alias-Challenge eine TXT-Record in der Zone acme.foo.example.org an. Let’s Encrypt kann nun über den CNAME den erstellten TXT-Record validieren. Anschließend wird das Zertifikat an den LE-Client ausgestellt.

Wird der LE-Client kompromittiert, sind damit zwar auch die auf ihm gespeicherten Private-Keys kompromittiert (was schon schlimm genug ist), es kann jedoch darüber hinaus nur die sogenannte DNS-Alias-Zone manipuliert werden. Eine Manipulation der eigentlichen Zone bleibt ausgeschlossen.

Installation des acme.sh-Clients

Um ein neu ausgestelltes bzw. erneuertes Zertifikat und den dazugehörigen Private-Key in einem Webserver zu verwenden, muss die Webserver-Konfiguration neu geladen werden. Dazu sind meist Root/sudoer-Rechte erforderlich. In diesem Tutorial wird der acme.sh-Client unter einem User mit sudo-Berechtigung installiert.

Hinweis: Das Projekt empfiehlt die Nutzung von sudo ausdrücklich nicht. Weitere Informationen finden sich unter dem Link: https://github.com/acmesh-official/acme.sh/wiki/sudo

Da ich glaube, zu wissen, was ich tue, werde ich hier optional die Einrichtung unter einem User mit sudo-Berechtigung dokumentieren. Befehle sind entsprechend mit oder ohne sudo auszuführen, je nachdem welcher User verwendet wird.

Zur Installation führt man folgende Kommandos aus (Quelle):

git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install

Durch die Installationsroutine werden folgende drei Aktionen durchgeführt:

  1. Erstellen und Kopieren von acme.sh in das HOME-Verzeichnis ($HOME): ~/.acme.sh/. Unterhalb dieses Verzeichnisses werden die ausgestellten Zertifikate abgelegt.
  2. Erstellen eines Alias für: acme.sh=~/.acme.sh/acme.sh.
  3. Erstellen eines täglichen cron job, welcher die Restlaufzeit der Zertifikate prüft und diese ggf. verlängert.

Beispiel eines Cron-Jobs:

1 0 * * * "/home/alice/.acme.sh"/acme.sh --cron --home "/home/alice/.acme.sh" > /dev/null

Nach der Installation meldet man sich am besten einmal neu an, damit der Alias für acme.sh genutzt werden kann.

Anlegen der CNAME-Records

Nun legen wir die CNAME-Records an, welche für den DNS-Alias-Mode benötigt werden (Quelle).

_acme-challenge.host.foo.example.org IN CNAME acme.foo.example.org
_acme-challenge.mein-schoener-host.bar.example.org IN CNAME acme.foo.example.org

Der vom DNS-Anbieter bereitgestellte TSIG-Schlüssel ist ausschließlich zum Erstellen von Records in der Zone acme.foo.example.org berechtigt. Mit dem CNAME-Record weisen wir quasi nach, dass wir die Kontrolle über die DNS-Zone haben und dort Ressource-Records erstellen dürfen, während der acme.sh-Client nur berechtigt ist Einträge in jenen Zonen zu erstellen, auf welche die CNAME-Records verweisen.

Dies geschieht aus Sicherheitsaspekten. Auf diese Art und Weise wird verhindert, dass ein kompromittierter Host mit acme.sh-Client die wichtigen Zonen überschreiben kann.

Beantragung, Ausstellen und Installation eines Zertifikats

Die Überschrift deutet bereits an, dass der folgende Prozess aus drei Schritten besteht. Ich beginne mit einem optionalen Schritt, in dem ich die notwendige Konfiguration für einen sudo-User erkläre.

Optional: Konfiguration für non-root-User

Wer den acme.sh-Client unter dem User root installiert hat, kann diesen Abschnitt überspringen. An dieser Stelle wird die Konfiguration eines sudo-Users beschrieben.

Verwendet wird dabei ein Useraccount, der bereits über sudo-Berechtigungen verfügt, sich bei der Verwendung von sudo jedoch mit einem Passwort authentisieren muss. Im Folgenden nennen wir diesen Useraccount Alice.

Anpassung der sudoers-Datei

Da für die Installation des Let’s Encrypt Zertifikats in einem Webserver ein Reload der Konfiguration des Webservers erforderlich ist und dies später automatisch (ohne Passworteingabe) geschehen soll, ist eine Anpassung der sudoers-Datei von Alice erforderlich.

Die sudoers-Datei von Alice (/etc/sudoers.d/alice) sieht zu Beginn wie folgt aus:

alice  ALL=(ALL) ALL

Um Alice nun das Recht zu geben, die Webserver-Konfiguration ohne Passworteingabe neu zu laden, wird folgende Zeile hinzugefügt. Dabei ist die Reihenfolge der Zeilen zu beachten (siehe sudoers(5)). Die Bearbeitung der Datei wird mit dem Kommando sudo visudo -f /etc/sudoers.d/alice durchgeführt.

alice  ALL=(ALL) ALL
alice  ALL=(ALL) NOPASSWD: /bin/systemctl reload httpd.service

Verzeichnis für TLS-Zertifikate und Private-Keys erstellen

Zur weiteren Nutzung durch den Webserver, sollen die Zertifikate und Private-Keys in einem Verzeichnis gespeichert werden, auf das Alice Schreibrechte hat. Der Verzeichnisname kann dabei abweichend vom folgenden Beispiel frei gewählt werden. Im Beispiel wird die Gruppe apache verwendet. Diese ist ggf. an das eigene System anzupassen:

sudo mkdir -m 750 /etc/letsencrypt
sudo chown alice.apache /etc/letsencrypt

Die folgenden Schritte sind für root und alice gleich. Nur muss alice einige Befehle halt mit sudo auführen. Diese sind entsprechend gekennzeichnet. root lässt ein führendes sudo einfach weg.

Zertifikat beantragen und austellen

Wie eingangs erwähnt, wird ein TSIG-Schlüssel und das Plugin dns_nsupdate genutzt, um dynamische Zonen-Updates auf dem Nameserver durchzuführen. Um den acme.sh-Client entsprechend zu konfigurieren, wird zuerst eine Key-Datei erstellt, welche den TSIG-Schlüssel in JSON-Notation enthält (vgl. Abschnitt Umfeld).

Wichtig: Der TSIG-Schlüssel erlaubt dynamische Zonen-Updates im DNS. Er ist geheim zu halten und bestmöglich zu schützen.

Der Name der Datei ist dabei frei wählbar. Ich empfehle die Datei im HOME-Verzeichnis des Users abzulegen, welcher den acme.sh-Client ausführt und die Datei nur für diesen User lesbar zu machen (chmod 0400 DATEINAME). Beispiel:

cat ~/.nsupdate.key
key "acme-key" {
  algorithm hmac-sha512;
  secret "SuperGeheim1111elf==";
};

chmod 0400 ~/.nsupdate.key

Als nächstes werden notwendige Informationen über den Nameserver und unseren TSIG-Key verfügbar gemacht. Die folgenden Kommandos sind einmalig auszuführen. Die Werte werden vom acme.sh-Client später automatisch in ~/.acme.sh/account.conf gespeichert (Quelle).

export NSUPDATE_SERVER="ns.example.org"
export NSUPDATE_KEY="/home/alice/.nsupdate.key"

Nun ist es endlich soweit, dass ein Zertifikat ausgestellt werden kann. Für die in diesem Tutorial verwendeten Werte lautet der Befehl dazu wie folgt:

acme.sh --issue --dns dns_nsupdate -d host.foo.example.org -d mein-schoener-host.bar.example.org --challenge-alias acme.foo.example.org

Der folgende Code-Block zeigt ein konkretes Beispiel unter Verwendung der Staging-Umgebung.

acme.sh --issue --staging --dns dns_nsupdate -d host.foo.example.org -d mein-schoener-host.bar.example.org --challenge-alias acme.foo.example.org

[Fr 4. Sep 09:52:41 CEST 2020] Using ACME_DIRECTORY: https://acme-staging-v02.api.letsencrypt.org/directory
[Fr 4. Sep 09:52:42 CEST 2020] Using CA: https://acme-staging-v02.api.letsencrypt.org/directory
[Fr 4. Sep 09:52:42 CEST 2020] Create account key ok.
[Fr 4. Sep 09:52:42 CEST 2020] Registering account: https://acme-staging-v02.api.letsencrypt.org/directory
[Fr 4. Sep 09:52:43 CEST 2020] Registered
[...]
[Fr 4. Sep 09:52:43 CEST 2020] Creating domain key
[Fr 4. Sep 09:52:44 CEST 2020] The domain key is here: /home/alice/.acme.sh/host.foo.example.org/host.foo.example.org
.key
[Fr 4. Sep 09:52:44 CEST 2020] Multi domain='DNS:host.foo.example.org,DNS:mein-schoener-host.bar.example.org'
[Fr 4. Sep 09:52:44 CEST 2020] Getting domain auth token for each domain
[Fr 4. Sep 09:52:46 CEST 2020] Getting webroot for domain='host.foo.example.org'
[Fr 4. Sep 09:52:46 CEST 2020] Getting webroot for domain='mein-schoener-host.bar.example.org'                                             
[Fr 4. Sep 09:52:46 CEST 2020] Adding txt value: 2tG2NCvV23KGUNCSGeVO3P_UVaOVAG4t0ehbv1cJbtY for domain:  _acme-challenge.acme.foo.example.org
[Fr 4. Sep 09:52:46 CEST 2020] adding _acme-challenge.acme.foo.example.org. 60 in txt "2tG2NCvV23KGUNCSGeVO3P_UVaOVAG4t0ehbv1cJbtY"
[Fr 4. Sep 09:52:46 CEST 2020] The txt record is added: Success.
[Fr 4. Sep 09:52:46 CEST 2020] Adding txt value: yFbL8EF6xQre3v3RfYiCYQ8X4KH0gykagD9_oRfIvgA for domain:  _acme-challenge.acme.foo.example.org
[Fr 4. Sep 09:52:46 CEST 2020] adding _acme-challenge.acme.foo.example.org. 60 in txt "yFbL8EF6xQre3v3RfYiCYQ8X4KH0gykagD9_oRfIvgA"
[Fr 4. Sep 09:52:46 CEST 2020] The txt record is added: Success.
[Fr 4. Sep 09:52:46 CEST 2020] Let's check each DNS record now. Sleep 20 seconds first.
[Fr 4. Sep 09:53:07 CEST 2020] Checking host.foo.example.org for _acme-challenge.acme.foo.example.org                       
[Fr 4. Sep 09:53:07 CEST 2020] Not valid yet, let's wait 10 seconds and check next one.
[Fr 4. Sep 09:53:20 CEST 2020] Checking mein-schoener-host.bar.example.org for _acme-challenge.acme.foo.example.org
[Fr 4. Sep 09:53:21 CEST 2020] Domain mein-schoener-host.bar.example.org '_acme-challenge.acme.foo.example.org' success.
[Fr 4. Sep 09:53:21 CEST 2020] Let's wait 10 seconds and check again.
[Fr 4. Sep 09:53:32 CEST 2020] Checking host.foo.example.org for _acme-challenge.acme.foo.example.org
[Fr 4. Sep 09:53:32 CEST 2020] Domain host.foo.example.org '_acme-challenge.acme.foo.example.org' success.
[Fr 4. Sep 09:53:32 CEST 2020] Checking mein-schoener-host.bar.example.org for _acme-challenge.acme.foo.example.org
[Fr 4. Sep 09:53:32 CEST 2020] Already success, continue next one.                                                                          
[Fr 4. Sep 09:53:32 CEST 2020] All success, let's return
[Fr 4. Sep 09:53:32 CEST 2020] Verifying: host.foo.example.org
[Fr 4. Sep 09:53:35 CEST 2020] Pending
[Fr 4. Sep 09:53:38 CEST 2020] Success
[Fr 4. Sep 09:53:38 CEST 2020] Verifying: mein-schoener-host.bar.example.org                                                               
[Fr 4. Sep 09:53:41 CEST 2020] Success
[Fr 4. Sep 09:53:41 CEST 2020] Removing DNS records.
[...]
[Fr 4. Sep 09:53:41 CEST 2020] Removed: Success
[Fr 4. Sep 09:53:41 CEST 2020] Verify finished, start to sign.
[Fr 4. Sep 09:53:41 CEST 2020] Lets finalize the order.
[Fr 4. Sep 09:53:41 CEST 2020] Le_OrderFinalize='https://acme-staging-v02.api.letsencrypt.org/acme/finalize/15482274/142528495'
[Fr 4. Sep 09:53:42 CEST 2020] Downloading cert.
[Fr 4. Sep 09:53:42 CEST 2020] Le_LinkCert='https://acme-staging-v02.api.letsencrypt.org/acme/cert/fa6e5a9922acccb49619cc8808f6f0916dc0'
[Fr 4. Sep 09:53:43 CEST 2020] Cert success.
[...]
[Fr 4. Sep 09:53:43 CEST 2020] Your cert is in  /home/alice/.acme.sh/host.foo.example.org/host.foo.example.org.cer
[Fr 4. Sep 09:53:43 CEST 2020] Your cert key is in  /home/alice/.acme.sh/host.foo.example.org/host.foo.example.org.key
[Fr 4. Sep 09:53:43 CEST 2020] The intermediate CA cert is in /home/alice/.acme.sh/host.foo.example.org/ca.cer
[Fr 4. Sep 09:53:43 CEST 2020] And the full chain certs is there:  /home/alice/.acme.sh/host.foo.example.org/fullchain.cer

Damit liegen alle benötigten Dateien auf unserem Host. Im nächsten Schritt werden diese in die korrekte Lokation installiert.

Installation der Zertifikate für Apache

Das folgende Beispiel gilt für den Webserver Apache und ist der Dokumentation des acme.sh-Clients entnommen. Auf der verlinkten Seite findet sich ein weiteres Beispiel für den Webserver NGINX.

Das Kommando im folgenden Beispiel enthält am Ende den Parameter --reloadcmd "sudo systemctl reload httpd.service. Das sudo ist notwendig, wenn man einen User mit sudo-Berechtigungen wie z.B. Alice nutzt (siehe oben). Als root lässt man sudo einfach weg. Ggf. muss der Name der Service-Unit an das eigene System angepasst werden.

acme.sh --install-cert -d host.foo.example.org --cert-file /etc/letsencrypt/host.foo.example.org.cer --key-file /etc/letsencrypt/host.foo.example.org.key --fullchain-file /etc/letsencrypt/host.foo.example.org.fullchain.cer --reloadcmd "sudo systemctl reload httpd.service"

Hat alles funktioniert, erzeugt obiger Befehl folgende Ausgabe:

[Fr 4. Sep 12:36:22 CEST 2020] Installing cert to:/etc/letsencrypt/host.foo.example.org.cer
[Fr 4. Sep 12:36:22 CEST 2020] Installing key to:/etc/letsencrypt/host.foo.example.org.key
[Fr 4. Sep 12:36:22 CEST 2020] Installing full chain to:/etc/letsencrypt/host.foo.example.org.fullchain.cer
[Fr 4. Sep 12:36:22 CEST 2020] Run reload cmd: sudo systemctl reload httpd.service
[Fr 4. Sep 12:36:22 CEST 2020] Reload success

Hinweis: Der Webserver bzw. VirtualHost des Webservers muss so konfiguriert werden, dass die Zertifikate aus dem entsprechenden Pfad auch verwendet werden. Diese Konfiguration ist nicht Gegenstand dieses Tutorials. Es wird hierzu auf die Dokumentation des genutzten Webservers verwiesen.

Die Dateiberechtigungen für oben installierte Dateien sind nach der Installation einmalig zu korrigieren und ggf. mit chown und chmod so zu konfigurieren, dass nur Alice und der Webserver-User Zugriff darauf haben. Wichtig: Der Private-Key darf unter keinen Umständen von allen Usern gelesen werden dürfen. Folgender Code-Block zeigt eine mögliche Berechtigung:

ls -l /etc/letsencrypt/
total 12
-rw-r-----. 1 alice apache 1964  4. Sep 15:09 host.foo.example.org.cer
-rw-r-----. 1 alice apache 3644  4. Sep 15:09 host.foo.example.org.fullchain.cer
-rw-r-----. 1 alice apache 1679  4. Sep 15:09 host.foo.example.org.key

Die Dateiberechtigungen bleiben bei einer Erneuerung des Zertifikats und beim Überschreiben der existierenden Dateien erhalten.

Die vorgenommenen Einstellungen und Befehle werden in der Datei ~/.acme.sh/account.conf gespeichert. In der Standard-Einstellung wird das Zertifikat automatisch alle 60 Tage erneuert, in den angegebenen Pfaden installiert und ein Neustart des Webservers durchgeführt.

Weiterführende Quellen und Links

  1. A Technical Deep Dive: Securing the Automation of ACME DNS Challenge Validation: https://www.eff.org/deeplinks/2018/02/technical-deep-dive-securing-automation-acme-dns-challenge-validation
  2. How-to install acme.sh: https://github.com/acmesh-official/acme.sh/wiki/How-to-install
  3. Install from Git: https://github.com/acmesh-official/acme.sh#2-or-install-from-git
  4. Set up Let’s Encrypt certificate using acme.sh as non-root user: https://gist.github.com/Greelan/28a46a33140b65c9a045573ca460f044

Datenträger unter Linux mit cryptsetup (LUKS) verschlüsseln

Ihr möchtet einen Datenträger wie z.B. eine Festplatte oder einen USB-Stick verschlüsseln, damit bei einem Verlust des Datenträgers nicht jeder ohne weiteres Zutun eure Daten lesen kann? Dann haben wir ein gemeinsames Ziel!

Im Folgenden beschreibe ich, wie unter Linux mit Hilfe des Programms cryptsetup eine Festplatte verschlüsselt werden kann. Dazu gehört die Beschreibung, wie das verschlüsselte Gerät anschließend zur Nutzung geöffnet wird und wie man es in die /etc/crypttab einträgt, um das Gerät automatisch beim Start des Rechners zu öffnen. Es handelt sich dabei um eine zusätzliche Festplatte. Wie die erste Festplatte eines Systems verschlüsselt werden kann ist hingegen nicht Gegenstand dieses Artikels. Hier hilft (hoffentlich) ein Blick in die Installationsanleitung der jeweiligen Linux-Distribution weiter.

Das Programm cryptsetup ist in allen gängigen Linux-Distributionen verfügbar. Falls nicht, kann es direkt von der Projekt-Homepage auf GitLab bezogen werden. Die hier gezeigten Kommandos funktionieren prinzipiell auf jedem Linux-System, auf dem cryptsetup verfügbar ist.

Bevor es losgeht noch ein Hinweis. Ich möchte ein verschlüsseltes Gerät erstellen, mit dem Ziel, dass nicht jeder die Daten einfach lesen kann, dem das Gerät in die Hände fällt. Dabei denke ich an Szenarien wie Verlust, Diebstahl, Verkauf etc. Die Daten vor dem Zugriff durch Sicherheitsbehörden, Geheimdiensten oder Schurkenstaaten zu schützen erfordert einen deutlichen höheren Aufwand und ist nicht Gegenstand dieses Artikels.

Ich verwende im Folgenden LUKS2. Wer stattdessen lieber dm-crypt verwendet, sei auf die Manpage cryptsetup(8) verwiesen.

Die zu verschlüsselnde Festplatte wird in diesem Tutorial als /dev/sdX bezeichnet. Dieser Bezeichner muss auf das tatsächlich zu nutzende Gerät angepasst werden. Wichtig: Wird versehentlich das falsche Gerät verschlüsselt gehen vorhandene Daten unwiederbringlich verloren!

LUKS-Container erstellen

Zur Erstellung eines LUKS-Containers wird der folgende Befehl ausgeführt und die Bildschirmanweisungen befolgt. Für die dabei abgefragte Passphrase gilt grundsätzlich: „Je länger und komplizierter, desto sicherer. Wobei es mehr auf die Länge als die Komplexität ankommt.“

Weitere Hinweise zur Passwort-Sicherheit bietet der Wikipedia-Artikel zu Passsatz.

$ sudo cryptsetup luksFormat --type luks2 /dev/sdX
WARNING: Device /dev/sdX already contains a 'dos' partition signature.

WARNING!
========
This will overwrite data on /dev/sdX irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/sdX: 
Verify passphrase:

Hinzufügen einer Backup-Passphrase

LUKS-Passphrasen werden in sogenannten Key-Slots gespeichert. Es stehen 8 Key-Slots zur Verfügung, welche von 0-7 nummeriert sind. Die Passphrase aus dem vorigen Abschnitt wurde in Slot 0 gespeichert.

Vergisst man die Passphrase, wird der Key-Slot oder der LUKS-Header beschädigt, ist ein Zugriff auf die Daten nicht mehr möglich. Um mich gegen die ersten beiden Fälle abzusichern, erstellte ich zwei Backup-Passphrasen, welche ich in den Key-Slots 3 und 8 speicherte. Wie man sich gegen den Verlust des LUKS-Headers schützt, beschreibe ich im folgenden Abschnitt.

$ # Hinzufügen der ersten Backup-Passphrase in Key-Slot 3
$ sudo cryptsetup luksAddKey /dev/sdX --key-slot 3
Enter any existing passphrase: 
Enter new passphrase for key slot: 
Verify passphrase:

$ # Hinzufügen der zweiten Backup-Passphrase in Key-Slot 8
$ sudo cryptsetup luksAddKey /dev/sdX --type luks2 --key-slot 8
Enter any existing passphrase: 
Enter new passphrase for key slot: 
Verify passphrase:

Für die Backup-Passphrasen gilt selbstverständlich das im vorangegangenen Abschnitt Beschriebene. Die einzelnen Passphrasen sollten von gleicher Güte sein.

Die Backup-Passphrasen sind an einem sicheren Ort aufzubewahren. Ich verwende dazu bspw. einen Passwort-Tresor (vgl. Sichere Passwörter und wie man sie verwaltet).

LUKS-Header sichern

Nun nützen alle Backup-Passphrasen nichts, wenn der LUKS-Header beschädigt wird. Daher empfehle ich diesen mit Hilfe des folgenden Kommandos in eine Datei zu sichern.

$ sudo cryptsetup luksHeaderBackup /dev/sdX --header-backup-file /var/tmp/luksHeaderBackup_2020-10-18

Die so erstellte Datei ist sicher — am besten offline und vom Datenträger getrennt — aufzubewahren. Mit Hilfe dieser Datei und einer Passphrase, welche bei Erstellung des Backups gültig war, kann ein defekter LUKS-Header und damit der Zugriff auf ein verschlüsseltes Gerät wiederhergestellt werden.

Ändert man im Laufe der Zeit in Key-Slots gespeicherte Passphrasen, löscht alte oder fügt neue hinzu, so ist eine erneute Sicherung des LUKS-Headers sinnvoll und angeraten.

LUKS-Container öffnen und nutzen

Bis jetzt haben wir auf dem Block-Gerät /dev/sdX einen verschlüsselten LUKS-Container erstellt, Backup-Passphrasen hinzugefügt und den LUKS-Header gesichert. Der folgende Code-Block zeigt, wie der LUKS-Container geöffnet und damit nutzbar gemacht wird. Dabei ist sdX_crypt ein Bezeichner, welcher für den Device Mapper verwendet wird. Dieser Bezeichner kann von euch frei gewählt werden.

$ sudo cryptsetup open /dev/sdX sdX_crypt
$ lsblk | grep sdX
sdX              8:16   0 111,8G  0 disk  
└─sdX_crypt    254:3    0 111,8G  0 crypt

Der so geöffnete LUKS-Container kann nun mit einem Dateisystem eurer Wahl formatiert werden. Folgender Code-Block zeigt ein Beispiel für ext4. Dies kann in Abhängigkeit zur Größe des LUKS-Containers einige Zeit dauern.

$ sudo mkfs.ext4 /dev/mapper/sdX_crypt
[...]
$ sudo blkid | grep sdX
/dev/sdX: UUID="Eine-furchbar-lange-UUID" TYPE="crypto_LUKS"
/dev/mapper/sdX_crypt: UUID="Eine-andere-furchbar-lange-UUID" TYPE="ext4"

Man beachte, dass der LUKS-Container direkt mit einem Dateisystem formatiert werden kann. Die Erstellung einer Partition ist nicht erforderlich.

Das erstellte Dateisystem kann anschließend wie gewohnt eingehängt werden.

$ sudo mount /dev/mapper/sdX_crypt /mnt

Mit den folgenden Kommandos wird das Dateisystem wieder ausgehängt und der LUKS-Container verschlossen. Damit liegen die Daten nur noch in verschlüsselter Form vor, bis sie das nächste Mal geöffnet werden.

$ sudo umount /dev/mapper/sdX_crypt
$ sudo cryptsetup close sdX_crypt
$ sudo cryptsetup status sdX_crypt
/dev/mapper/sdX_crypt is inactive.

Verschlüsseltes Dateisystem bei Startvorgang des Rechners öffnen und einhängen

Soll das erstellte Dateisystem /dev/mapper/sdX_crypt bereits beim Start des Rechners eingehängt werden, ist folgende Reihenfolge einzuhalten:

  1. LUKS-Container sdX_crypt mit Hilfe der /etc/crypttab öffnen
  2. Dateisysteme aus /etc/fstab einhängen

Die Einträge in den entsprechenden Dateien sehen in meinem Fall wie folgt aus. In /etc/crypttab wird dabei die UUID des Gerätes /dev/sdX verwendet.

$ sudo cat /etc/crypttab
sdX_crypt UUID="Eine-furchbar-lange-UUID" none luks,discard

$sudo cat /etc/fstab
/dev/mapper/sdX_crypt /mnt ext4 defaults 0 0

Man beachte, dass der Rechner nun den Startvorgang unterbricht und zur Eingabe der Passphrase zum Öffnen des LUKS-Containers auffordert. Anschließend wird der Startvorgang fortgesetzt.

Damit sind wir eigentlich am Ende des Tutorials angelangt. Wie fandet ihr es? War es verständlich genug, um folgen zu können und Eingangs erwähnte Ziele zu erreichen?

Wer noch Zeit und Lust hat, kann gerne weiterlesen. In den folgenden Abschnitten werde ich als Zugabe noch beschreiben, wie man Key-Slots löscht und einen LUKS-Header aus einem Backup wiederherstellt.

Key-Slots löschen

Mit dem folgenden Befehl werden sämtliche Key-Slots des LUKS-Containers gelöscht. Ein Zugriff auf den LUKS-Container ist anschließend nicht mehr möglich. Die Angabe eines Passworts ist nicht erforderlich.

Warnung: Dieser Vorgang kann nicht rückgängig gemacht werden.

$ sudo cryptsetup erase /dev/sdX

WARNING!
========
This operation will erase all keyslots on device /dev/sdb.
Device will become unusable after this operation.

Are you sure? (Type uppercase yes):

Das war’s.

LUKS-Header aus Sicherung wiederherstellen

Und nun halte ich noch fest, wie man einen LUKS-Header und die darin enthaltenen Key-Slots aus einer Datensicherung wiederherstellen kann.

$ sudo cryptsetup luksHeaderRestore /dev/sdX --header-backup-file /tmp/luksHeaderBackup_2020-10-18 

WARNING!
========
Device /dev/sdX already contains LUKS2 header. Replacing header will destroy existing keyslots.

Are you sure? (Type uppercase yes):

Uns schon kann man wieder auf seinen LUKS-Container zugreifen.

Reflexion

Um meine Festplatte zu verschlüsseln und diesen Beitrag zu schreiben, habe ich einige Zeit in der Manpage cryptsetup(8) und auf der Projekt-Seite gelesen. Nur mit der Manpage allein wäre mir eine Nutzung vermutlich erst nach deutlich längerer Zeit gelungen.

Dabei vermisse ich in der Manpage vor allem eine Inhaltsübersicht und Beispiele, mit denen man sich gängige Aufgaben schnell ins Gedächtnis rufen kann. Zwar existiert seit ca. zwei Jahren ein Ticket zur Überarbeitung der Manpage, doch fehlt es bei den am Projekt beteiligten Personen wie so oft an der Zeit. Diese wird primär zur Arbeit am Code genutzt. Für die Dokumentation bleibt keine Zeit übrig.

Aktuell erkundige ich mich auf der Mailling-Liste, wie man am besten dazu beitragen kann, die Manpage zumindest in Teilen zu verbessern. Mal sehen, was sich da machen lässt.

Da man vermutlich nicht täglich mit cryptsetup arbeitet, ist eine gute Dokumentation um so wichtiger, da vermutlich niemand alle notwendigen Befehle dauerhaft im Gedächtnis behält.

Mit diesem Tutorial habe ich mir meine eigene Dokumentation für meine häufigsten Anwendungsfälle geschaffen. Wenn ihr sie ebenfalls nützlich findet, freut mich dies umso mehr.

Social-Red_Hat-Accelerators-Personal_Post-Twitter-RGB

Das Red Hat Accelerator Programm ist offiziell gestartet

In seiner heutigen Presseerklärung gibt Red Hat den offiziellen Start des Red Hat Accelerators Programms bekannt.

Die Red Hat Accelerators sind eine einzigartige Gemeinschaft, bestehend aus Open Source IT-Enthusiasten. Ich bin stolz Mitglied dieser Gemeinschaft zu sein. Dadurch habe dich die Möglichkeit:

  • Mich mit Gleichgesinnten zu vernetzen
  • Frühzeitig einen Blick auf neue Technologien und Entwicklungen von Red Hat zu werfen
  • Mit Experten von Red Hat zu interagieren
  • Die Produktentwicklung mit zu beeinflussen

Wir sind Kunden und Partner, welche gern über IT-Themen diskutieren, uns austauschen und Red Hat ehrliches Feedback zur ihren Produkten zukommen lassen.

Und diese Möglichkeiten stehen auch Dir offen!

Wenn auch Du ein Teil dieser außergewöhnlichen Gemeinschaft werden möchtest, erfährst du alles notwendige für deine Bewerbung unter diesem Link.

Vielen Dank an Andi, Grace und Jeff, welche alles dafür geben, damit wir uns in diesem Programm wohlfühlen.

LinuxDay 2020 am 10. Oktober

Online GNU/LinuxDay in Vorarlberg – am 10. Okt. 2020

Wie so viele andere Veranstaltungen in diesem Jahr findet auch der LinuxDay in Vorarlberg dieses Jahr ausschließlich online statt.

Die Linux User Group (LUG) Vorarlberg schickt sich an, die Veranstaltung erstmals im Cyberspace und auf Basis von Open Source Software auszurichten. Ich denke sowohl die Veranstalter, Vortragende und Teilnehmer sind auf diese Premiere gespannt.

Das diesjährige Vortragsprogramm bietet insgesamt 12 Vorträge. Diese verteilen sich auf zwei Blöcke mit jeweils sechs Vorträgen. Von mir ist in diesem Jahr auch wieder ein Beitrag dabei. Um 11:00 Uhr werde ich euch zwei kleine Projekte vorstellen, mit denen sich ein Spiegelserver und ein Patch-Management für Red Hat Enterprise Linux realisieren lassen.

Ich persönlich finde es sehr schade, dass diese und viele weitere Veranstaltungen dieser Art in diesem und vermutlich auch im nächsten Jahr ausschließlich im Cyberspace abgehalten werden können. Die Gründe dafür verstehe ich und kann die Entscheidung nachvollziehen. Doch geht das, was ich an diesen Veranstaltungen am meisten schätze, derzeit verloren.

Für mich stellt der Besuch des LinuxDay eine willkommene Abwechslung zum Alltag dar. Die Vorfreude beginnt bereits Tage vor der Anreise. Auf diesen Veranstaltungen treffe ich Gleichgesinnte in lockerer und ungezwungener Atmosphäre. Einige Menschen treffe ich tatsächlich ausschließlich am Rande dieser Veranstaltungen. Bei Kaffee, Mate und Bier lässt sich fachsimpeln, über aktuelle Entwicklungen diskutieren und man fühlt sich verstanden. Dies alles geht bei reinen Online-Konferenzen in meinen Augen verloren. Daher hoffe ich, dass möglichst bald ein Impfstoff gegen das Corona-Virus gefunden wird und wir uns vielleicht schon 2022 vor Ort wiedersehen können.

tdps.service — Service-Unit für den TeamDrive Personal Server

Kaum eine Software verwende ich so lange wie TeamDrive. Die ersten Artikel dazu in diesem Blog stammen bereits aus dem Jahr 2011 [0], [1].

Nachdem ich den TeamDrive Personal Server schon auf einem NAS installiert und als Dienst konfiguriert habe, dokumentiere ich in diesem Artikel die Erstellung einer Systemd-Service-Unit. Dazu sei gesagt, dass ich kein Experte für Systemd-Units bin. Tatsächlich kenne ich mich nichtmal besonders gut damit aus. Folgende Lösung funktioniert auf meinem Server. Anregungen zur Verbesserung der Service-Unit nehme ich gern in den Kommentaren entgegen.

Installation des TeamDrive Personal Server

Zuerst muss der TeamDrive Personal Server heruntergeladen und installiert werden. Dabei hilft das dazugehörige Handbuch. Auch wenn dieses schon einige Jahre auf dem Buckel hat, sind die enthaltenen Informationen weiterhin aktuell.

Da die Installation hier im Blog bereits einmal beschrieben wurde, gehe ich hier im Detail nicht weiter darauf ein. Im vorliegenden Fall wurde die Software im Verzeichnis /opt/tdps installiert. Darüber hinaus wurde ein Benutzer tdps erstellt, welchem das Verzeichnis /opt/tdps und die darin enthaltenen Dateien gehören.

Systemd-Service-Unit tdps.service

Ich habe den TeamDrive Personal Server (TDPS) auf einem Debian 10 System installiert. Um diesen wie alle übrigen Dienste mit dem Programm systemctl verwalten zu können, habe ich die Datei /etc/systemd/system/tdps.service mit folgendem Inhalt erstellt:

[Unit]
Description="TeamDrive Personal Server"
After=network.target

[Service]
User=tdps
PIDFile=/opt/tdps/tdpsd.pid
ExecStart=/opt/tdps/tdpsd -c /opt/tdps/tdps.config -m /opt/tdps/mime.types -w /opt/tdps
ExecStop=/opt/tdps/stop-tdps -p /opt/tdps/tdpsd.pid
KillMode=process
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full

[Install]
WantedBy=multi-user.target

Im Abschnitt [Unit] findet sich eine kurze Beschreibung der Service-Unit. Die Option After=network.target gibt an, dass diese Unit erst gestartet werden soll, wenn das Netzwerk zur Verfügung steht. Dies ist Voraussetzung, um den Dienst über das Netzwerk nutzen zu können.

Die Zeile im letzten Abschnitt [Install] definiert, dass diese Unit Bestandteil des multi-user.target ist und mit diesem geladen wird.

Der Abschnitt [Service] definiert die für den Dienst relevanten Parameter. Die gewählten Optionen werde ich im Folgenden erläutern.

User= gibt den Namen des Benutzers an, mit dessen Rechten der Dienst ausgeführt werden soll. In diesem Fall wird der extra für diesen Zweck erstellte User tdps verwendet.

PIDFile= gibt den Pfad an, wo der Dienst seine PID speichert. Der Service-Manager liest die PID des Hauptprozess aus dieser Datei, nachdem der Service gestartet wurde.

ExecStart= gibt das Kommando mit allen notwendigen Argumenten an, um den Dienst zu starten. Ich habe hier ein wenig mit verschiedenen Aufrufen experimentiert. Dabei habe ich verschiedene Möglichkeiten gefunden, den Dienst erfolgreich zu starten. Worin die Unterschiede im Aufruf genau bestehen, kann ich leider nicht sagen. Am Ende habe ich mich für obige Kommandozeile entschieden, die ich im TeamDrive-Forum gefunden habe. Aus diesem Foren-Beitrag habe ich auch Stumpf die Option KillMode=process übernommen. Zur Option selbst kann ich (noch) nicht viel sagen. Dies änderst sich vielleicht noch, da ich mich noch etwas damit beschäftigen möchte.

Mit ExecStop= gibt man entsprechend an, wie der Dienst zu stoppen ist. Auch hier stammt die Kommandozeile aus oben verlinktem Foren-Thread.

Die nächsten drei Optionen PrivateTmp=, ProtectHome= und ProtectSystem= dienen dazu den Dienst zu härten. Durch PrivateTmp=yes erhält der gestartete Prozess einen eigenen Dateisystem-Namespace für /tmp und /var/tmp. So kann der Prozess nicht auf die Dateien anderer Prozesse und Benutzer in den normalen Verzeichnissen /tmp und /var/tmp zugreifen. Mit ProtectHome=yeswird der Zugriff des Dienstes auf die Verzeichnisse /home, /root und /run/user verhindert. ProtectSystem=full sorgt dafür, dass die Verzeichnisse /boot, /etc und /usr im Nur-Lese-Modus für den Prozess zur Verfügung stehen. Damit ist sichergestellt, dass der von dieser Unit gestartete Prozess keine Dateien innerhalb dieser Verzeichnisse verändern kann.

Die drei im vorhergehenden Abschnitt genannten Optionen stellen einen zusätzlichen Schutz dar. Zwar darf der Benutzer tdps schon aufgrund der Datei- und Verzeichnisberechtigungen nicht in den genannten Verzeichnissen schreiben und Dateien verändern bzw. diese überhaupt lesen, doch bieten diese Optionen einen zusätzlichen Schutz und greifen auch noch, wenn jemand Schindluder mit den Berechtigungen getrieben hat. Daher halte ich es für sinnvoll diese Optionen wenn möglich in allen Service-Units zu nutzen.

Neben den drei hier vorgestellten Optionen gibt es noch einige weitere, welche im englischsprachigen Artikel „Mastering systemd: Securing and sandboxing applications and services“ nachgelesen werden können. Ich finde diese so sinnvoll, dass ich mich ehrlich gesagt frage, warum die genannten Einstellungen nicht der Standard sind und man diese editieren muss, wenn man entsprechende Zugriffe explizit erlauben möchte.

Damit ist alles getan und dokumentiert. Der TDPS lässt sich mit oben beschriebener Service-Unit starten und stoppen. Den Status abfragen kann man selbstverständlich auch.

Es bleibt ein kleiner Schönheitsfehler. Wird der Dienst mittels sudo systemctl stop tdps.service gestoppt, endet die Unit im Status „failed“. Warum das so ist, habe ich noch nicht herausgefunden. Ich vermute, es hängt damit zusammen, dass der Dienst mittels SIGTERM beendet wird. Bin mir an dieser Stelle jedoch nicht sicher. Falls von euch jemand eine Idee dazu hat, freue ich mich über euren Kommentar.

Wie schreibt ihr eure Service-Units? Welche Optionen sollten eurer Meinung nach in keiner Unit fehlen? Wenn ihr mögt, lasst uns gerne in den Kommentaren darüber diskutieren.

Ältere Artikel zu TeamDrive in diesem Blog

Software-Pakete mit Ansible installieren

In diesem sehr kurzen Beitrag möchte ich euch zeigen, wie ihr mit Ansible einen definierten Satz an Software-Paketen auf euren Linux-Hosts installieren könnt. Dies ist z.B. dann nützlich, wenn ihr bei der Provisionierung neuer Systeme sicherstellen möchtet, dass ein bestimmter Satz an Paketen vorhanden ist.

Natürlich kann man diese Aufgabe auch auf verschiedenen anderen Wegen lösen. Dies ist halt der Ansible-Weg. ;-)

---
- hosts: all
  tasks:
  - name: Install package baseline
    yum:
      name:
        - bind-utils
        - net-tools
        - chrony
        - ed
        - yum-utils
        - vim-enhanced
        - man-pages
        - strace
        - lsof
        - tcpdump
        - setroubleshoot-server
        - setroubleshoot
        - bash-completion
      state: latest
      update_cache: yes

Das obige Playbook zeigt ein einfaches Beispiel, wie auf einem RHEL/CentOS 7 System eine Liste von Paketen installiert werden kann. Dazu wird das Ansible-Modul yum verwendet. Der Parameter ’state‘ gibt an, dass immer die jeweils akutellste Version eines Pakets installiert werden soll. Mit ‚update_cache‘ wird definiert, dass der lokale Cache aktualisiert wird, bevor ein Paket zur Installation ausgewählt wird.

Für auf Debian/Ubuntu basierende Systeme gibt es das Modul apt. Für Fedora und RHEL/CentOS ab Version 8 nutzt man das Modul dnf.

Darüber hinaus gibt es noch das generische Modul package. Bei diesem ist jedoch zu beachten, dass die unterschiedlichen Paketmanager wie YUM und APT zum Teil unterschiedliche Paketnamen verwenden. Da ‚package‘ diese nicht automatisch übersetzt ist eine Verwendung über verschiedene Distributionen hinweg nicht ohne weiteres möglich. Daher empfinde ich dieses Modul als nutzlos.

Konfiguration der Host-Firewall mit Ansible

In diesem kurzen Beitrag möchte ich euch zeigen, wie man mit Hilfe von Ansible die Host-Firewall (firewalld) konfigurieren kann. Dies ist z.B. dann nützlich, wenn man die identische Konfiguration auf mehreren Hosts ausbringen möchte.

Bevor es an die Freigabe spezifischer Ports und Services in der Host-Firewall geht, wird zuerst sichergestellt, dass der Dienst firewalld installiert, aktiviert und gestartet ist. Dazu dienen die Ansible-Module yum und service. Folgendes Playbook zeigt beispielhaft, wie diese genutzt werden können, um vorstehende Anforderungen zu erfüllen:

---
# Install, activate and start firewalld

- hosts: foo.example.com
  tasks:
  - name: Make sure firewalld is installed
    yum:
      name: firewalld
      state: latest

  - name: Activate and start firewalld service
    service:
      name: firewalld
      enabled: yes
      status: started

Bei Verwendung einer auf Debian basierenden Distribution ist statt yum das Modul apt zu verwenden.

Um jetzt z.B. die Services HTTP und HTTPS in der lokalen Host-Firewall freizugeben, kann obiges Playbook um die folgenden Abschnitte, unter Verwendung des Ansible-Moduls firewalld, ergänzt werden:

[...]
  - name: Enable immediate and permanent access to HTTP
    firewalld:
      service: http
      permanent: yes
      immediate: yes
      state: enabled

  - name: Enable immediate and permanent access to HTTPS
    firewalld:
      service: https
      permanent: yes
      immediate: yes
      state: enabled

Aktuell ist es leider noch nicht möglich dem Parameter ’service‘ eine Liste zu übergeben. Auf GitHub existiert jedoch bereits ein RFE für diese Funktion.

Persönliche Bewertung von Red Hat Insights

Dies ist der letzte Teil meiner Artikelserie „Einführung in Red Hat Insights“. An dieser Stelle schließe ich mit meinem Test ab, entferne die Systeme aus dem Cloud-Dienst und nehme eine persönliche Bewertung der SaaS-Anwendung vor.

Hinweis: Ich habe den Dienst im Rahmen meiner beruflichen Tätigkeit im Bielefelder IT-Service Zentrum (BITS) der Universität Bielefeld getestet. Dieser Artikel spiegelt meine persönliche Ansicht zu Red Hat Insights wider. Des Weiteren weise ich darauf hin, dass ich Mitglied der Red Hat Accelerators Community bin (siehe „Zu meiner Person“).

Systeme aus Insights entfernen

Im Einführungsartikel habe ich ein kleines Ansible-Playbook verwendet, um den insights-client und weitere benötigte Pakete auf den teilnehmenden Hosts zu installieren. Dieses wird nun angepasst und dazu genutzt, die Systeme aus Insights zu entfernen und die nicht mehr benötigten Pakete zu deinstallieren:

---
- hosts: rh-insights-poc # Gruppe aus dem Ansible-Inventory
  tasks:


  - name: Register insights-client
    command: insights-client --unregister

  - name: Make sure required packages are present
    yum:
      name:
        - openscap-scanner
        - scap-security-guide
        - insights-client
      state: absent

Nur wenige Minuten nach Ausführung des Playbooks sind die Systeme aus Insights gelöscht.

Abschließende Bewertung von Red Hat Insights

Meiner Ansicht nach ist es Red Hat mit Insights gelungen, einen nützlichen Dienst bereitzustellen, der einen deutlichen Mehrwert für bestehende Subskriptionen bietet. Und dies ohne Mehrkosten. Das Dashboard ist übersichtlich, gut strukturiert und lässt sich intuitiv bedienen. Es bietet von zentraler Stelle aus Zugriff auf vielfältige Informationen zu den eigenen Systemen und Artikeln in den Wissens- und Lösungs-Datenbanken von Red Hat und weiteren Unternehmen.

Insgesamt war mir die Erkundung von Insights eine Freude und hat einige neue Erkenntnisse zu Tage gefördert, die andernfalls vermutlich noch lange im Dunkeln verborgen geblieben wären. Dies gilt insbesondere für den Advisor und das Vulnerability Management. Diese beiden Komponenten stellen für mich die wertvollsten Bestandteile von Insights dar.

Auch die übrigen Komponenten Compliance, Patch und Drift machen einen guten Eindruck. Für Sysadmins, die Compliance nach gewissen Standards wie z.B PCI-DSS oder HIPAA nachweisen müssen, ist die gleichlautende Komponente ein hilfreiches Werkzeug. Patch und Drift sind nette Anwendungen, welche noch ein wenig Potenzial für Verbesserungen haben, den Dienst jedoch gut ergänzen.

Nicht näher betrachtet habe ich das Rollen- und Rechte-Konzept von Insights. Grundsätzlich werden die im Customer Portal existierenden Benutzer in die Insights-Benutzerverwaltung kopiert und dort als Standard-Benutzer berechtigt. Damit darf jeder Benutzer erstmal alles. Dies finde ich nicht ganz so geschickt. Auch wenn man die Rechte der einzelnen Nutzer mit vorhandenen Rollen anschließend beschränken kann, hätte ich mir hier einen anderen Ansatz gewünscht. Zum Beispiel hätte man einem Organisations-Administrator das Recht einräumen können, weitere Benutzerkonten zu importieren und entsprechend zu berechtigen. Vielleicht ist unter meinen Lesern jemand, der sich mit diesem Thema bereits intensiver beschäftigt hat. In diesem Fall freue ich mich, wenn Sie/Er die gemachten Erfahrungen mit uns teilt.

Doch wo Licht ist, gibt es meist auch Schatten. Denn für die Funktionsweise des Dienstes ist es notwendig, dass auf den angeschlossenen Systemen umfangreiche Informationen gesammelt und an den Cloud-Dienst übertragen werden. Dieser wird auf OpenShift innerhalb von AWS (US East) betrieben. Auch wenn der Dienst keine personenbezogenen Daten sammelt (oder dies zumindest zu vermeiden versucht), erhält der Dienstbetreiber detaillierte Informationen über vorhandene Schwachstellen und Konfigurationsfehler der eigenen Systeme. Aus den aggregierten Daten lässt sich eine Karte der eigenen IT-Infrastruktur mit ihren Schwachstellen und potenziellen Einfallstoren erstellen.

Ich persönlich tue mich deshalb schwer mit dem Gedanken, all unsere RHEL-Systeme an den Dienst anzubinden. Davon abgesehen bin ich kein Jurist und kann die rechtliche Seite einer möglichen Nutzung gar nicht abschließend beurteilen. Sysadmins sollten hier frühzeitig das Gespräch mit ihren Vorgesetzten, Informationssicherheits- und Datenschutzbeauftragten suchen, bevor sie sich bereits mit einem Test des Cloud-Dienstes in die Nesseln setzen.

Doch vielleicht erhört das Insights-Produkt-Team eines Tages das Flehen von mir und weiteren Kunden aus Deutschland bzw. Europa und stellt eine On-Premises-Variante des Dienstes, z.B. in Form einer virtuellen Appliance, bereit. Ohne zu wissen, wie meine Vorgesetzten dazu stehen, wäre mir diese sogar Geld wert. Bis es soweit ist, wird uns eine ausgedehnte Nutzung von Insights nicht möglich sein.

Red Hat Insights – Patch and Drift

Nein, dies ist nicht der Titel eines Kinofilms mit schnellen Autos. Dies ist der fünfte Artikel über meinen Test von Red Hat Insights. In diesem beschäftige ich mich mit den Anwendungen Patch und Drift.

Patch

So simpel wie der Name, ist auch die Funktion, die sich hinter diesem Menüpunkt verbirgt.

In Bild 1 würde man eine Übersicht der verfügbaren Red Hat Advisories sehen, welche auf den verbundenen Systemen noch nicht installiert sind. Da in diesem Fall alle angebundenen Systeme voll durchgepatcht sind, gibt es hier aktuell nichts zu sehen.

Bild 2 zeigt die verfügbaren Advisories pro Host. Auch hier gibt es aktuell nichts zu sehen, da die Systeme gerade aktualisiert wurden.

Ich habe vorstehend zwei Sätze gestrichen. Zwar waren meine Systeme durchgepatcht. Dass Patch keine Advisories anzeigt hat jedoch einen anderen Grund. Patch funktioniert nur dann korrekt, wenn die angebundenen Systeme die original RHEL-Upstream-Repos verwenden. In meinem Fall werden diese jedoch über einen lokalen Spiegelserver bereitgestellt. Obwohl dieser ebenfalls über sämtliche Erratas verfügt, werden diese von Patch nicht berücksichtigt. Siehe hierzu auch Bugzilla 1843860.

Diese Anwendung ist ganz nett, stellt allein aber keinen Grund für eine Nutzung von Insights dar. Zum einen können Errata-Informationen im Customer Portal per E-Mail abonniert werden und zum anderen kann auf jedem System mittels sudo yum updateinfo list geprüft werden, ob Advisories verfügbar sind. Und darüber hinaus funktioniert die Anwendung wie oben erwähnt in meiner Umgebung auch gar nicht.

In unserer Umgebung stellen wir mittels unseres Patch-Managements sicher, dass mindestens einmal im Monat alle verfügbaren Red Hat Security Advisories auf unseren Systemen installiert werden. Es schmerzt mich daher nicht, Patch nicht nutzen zu können.

Drift

Wer die Hostprofile von VMware kennt und schätzt, wird sich hier schnell wiederfinden. Unter diesem Punkt können Systeme miteinander verglichen und auf Unterschiede hin untersucht werden. Darüber hinaus ist die Erstellung von Baselines möglich, gegen die weitere Systeme geprüft und abgeglichen werden können.

Bild 3 zeigt den Vergleich zweier Systeme. Dabei wurde die Anzeige auf Unterschiede und unvollständige Datensätze gefiltert. So sieht man zum Beispiel, dass unzip nur auf einem der beiden Hosts installiert ist.

screenshot-drift-comparison.png
Bild 3: Gefilterte Ansicht von zwei Systemen in Drift Comparison

Darüber hinaus zeigt Bild 3, dass auf den beiden Systemen Pakete gleichen Namens jedoch für verschiedene Architekturen installiert sind. In diesem Fall trügt die Anzeige jedoch. Denn die drei genannten Pakete sind jeweils für i686 als auch für x86_64 auf beiden Systemen installiert.

In der getesteten Version bietet Drift noch keine Unterstützung multipler Werte für einen sogenannten fact. Es ist geplant diese Funktionalität in einem kommenden Release hinzuzufügen. Siehe dazu auch Bugzilla 1841561.

Ich tue mich ein wenig schwer damit, diese Anwendung zu bewerten. Auf der einen Seite bietet sie eine nette Möglichkeit Systeme miteinander zu vergleichen, auf der anderen Seite habe ich sie bis heute nicht vermisst. Für Vergleiche von Paketlisten und Konfigurationsdateien bevorzuge ich doch immer noch althergebrachte Kommandozeilen-Werkzeuge. Ich tendiere daher dazu — wie zuvor schon bei Patch — zu sagen: „Nette Zusatz-Funktion. Jedoch allein kein Grund Insights zu nutzen.“

Mit diesem Blick auf Patch und Drift endet meine Erkundung von Red Hat Insights. In einem folgenden Artikel werde ich schildern, wie die Systeme wieder aus Insights entfernt werden können und eine persönliche Bewertung vornehmen.