TokkNet

Passwortlogin über SSH unter Ubuntu deaktivieren

Oder: Warum Sicherheitseinstellungen immer getestet werden müssen
Tokk EN 207 Wörter ~1 Min.

Eine der ersten Dinge, die ich bei einem neuen Server immer anpasse ist die sshd_config, der Login über SSH mittels Passwort wird deaktiviert:

PubkeyAuthentication yes
ChallengeResponseAuthentication no
PasswordAuthentication no
PermitEmptyPasswords no
KbdInteractiveAuthentication no
UsePAM no

Normalerweise geht man davon aus, das die Einträge funktionieren. Meist testet man den Login dann vom eigenen PC aus und stellt zufrieden die Verwendung des Zertifikates fest.

Cloud Init

Natürlich wird Ubuntu aber heutzutage mit Cloud-Init ausgeliefert und seit Ubuntu 20.04 bringt dies direkt eine neue Config-Datei namens /etc/ssh/sshd_config.d/50-cloud-init.conf mit, die eine einzige Zeile enthält:

PasswordAuthentication yes

Da das Einbinden des Verzeichnisses sshd_config.d sehr weit oben in der sshd_config stattfindet, ist dies fast immer das erste Vorkommen der PasswordAuthentication Direktive. Das bedeutet, dass der hier angegebene Wert erhalten bleibt und die Passwortauthentifizierung trotz aller anderen Einstellungen aktiviert bleibt.
Um die Möglichkeit, sich mit einem Passwort anzumelden, vollständig zu deaktivieren, muss diese Datei daher gelöscht oder bearbeitet werden. Da diese Datei jedoch nur einem Zweck dient, kann sie mit gutem Gewissen gelöscht werden.

Abschließende Bemerkungen

  1. Dieser Sachverhalt zeigt deutlich, dass Sicherheitseinstellungen immer getestet werden müssen, egal wie sorgfältig man die Konfiguration durchführt, und zwar auch aus der Sicht eines externen Kontextes, in diesem Fall die Anmeldung ohne eigenes Zertifikat zu erzwingen.
  2. WTF Canonical?

Unpriviligertes Binding an priviligierte Ports

Ports unter 1024 an User-Prozesse binden
Tokk EN 167 Wörter ~1 Min.

Normalerweise erlaubt es der Linux-Kernel nicht, dass sich unprivilegierte Prozesse an Ports unter 1024 binden. Daher laufen die meisten (Web-) Server-Prozesse als root. Sicherheitstechnisch ist es natürlich nicht ideal, das gerade die Prozesse, welche sich um die Bearbeitung von Anfragen aus dem Internet kümmern umfassende Rechte haben, da dies im Falle einer feindlichen Übernahme des Prozesses natürlich auch direkt zu Root-Rechten auf dem ganzen Systems führt.
An dieser Stelle bietet Systemd jedoch die Möglichkeit, unserem Service die Bindung an die Ports zu erlauben, in dem man dem entsprechenden Prozess per AmbientCapabilities =CAP_NET_BIND_SERVICE die Berechtigung erteilt, sich an die Ports unter 1024 zu binden. Eine Übersicht über alle anderen erteilbaren Berechtigungen gibt es zum Beispiel in der Linux Man Page zu den Capabilities.

Bei der Gelegenheit kann man direkt noch per CapabilityBoundingSet=CAP_NET_BIND_SERVICE einschränken, das der Service nur diese Berechtigung bekommen darf und keine anderweitigen bekommen kann Die Unit-Datei sollte dann so aussehen:

[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

Am besten kann man solche Änderungen als Drop-In in einer eigenen Override-Datei anlegen.

Unerreichbare Resourcen unmounten

ohne reboot
Tokk 136 Wörter ~1 Min.

Wenn Netzwerkresourcen plötzlich nicht mehr erreichbar sind oder USB-Platten ausfallen kann es vorkommen, das Linux diese noch als gemounted aufführt, jeglicher Versuch in den Verzeichnissen zu arbeiten führt jedoch zu einem hängen des Prozesses.
Auch das aushängen der entsprechenden Ordner klappt in diesem Fall oft nicht mehr, da der Kernel im Hintergrund noch versucht schreibvorgänge zu Ende zu bringen und Resourcen zu schließen.

in so einem Fall können die Optionen -l oder -f helfen.

umount -l, verfügbar ab Kernel 2.4.11, hängt das Laufwerk aus und versucht dann im Hintergrund alle Resourcen aufzuräumen.
umount -f - wie bei den meisten anderen befehlen bedeutet -f force und bewirkt das sofortige aushängen ohne Rücksicht auf Konsequenzen.

Obligatorische Warnung

Das die hier aufgeführten Befehle zu Datenverlust führen können erwähne ich hier nur der Vollständigkeithalber, da es eigentlich klar sein sollte

Nicht reagierendes System neu starten

Sogar wenn kein Dateisystem unter / verfügbar ist
Tokk 208 Wörter ~1 Min.

Ab und an kann es passieren, dass ein System sich nicht mehr beenden lässt. Sei es, weil der Kernel versucht Hintergrundaufgaben abzuschließen oder kein Dateisystem mehr vorhanden ist (z.B. durch ein (meist versehentliches) erzwungenes unmounten von /) und somit die Executables für systemctl, reboot etc. einfach fehlen.
Sitzt man direkt am Rechner hilft natürlich der Ein-/Ausschalter aber oft ist die Sache ja nicht so einfach.

Mit vorhandenem Dateisystem

Wenn noch ein Dateisystem eingebunden ist, kann der Befehl reboot verwendet werden, mit einem der drei folgenden Möglichkeiten:

  • reboot -f: Killt alle Prozesse, unmounted Dateisysteme (oder hängt sie nur lesbar ein), startet dann neu
  • reboot -ff: Startet das System sofort neu, ohne Prozesse vorher zu beenden oder Dateisysteme zu unmounten
  • reboot -n: Führt keine Syncronisation der eingebundenen Dateisysteme durch.

Die ersten beiden Befehle können auch durch systemctl --force bzw. systemctl --force --force ersetzt werden, wenn der Befehl reboot nicht verfügbar ist.

Ohne vorhandes Dateisystem

Ohne Dateisystem gibt es die Möglichkeit, einen SystemRequest abzusetzen, der das System direkt und ohne Ausführung irgendwelcher Anwendungen neu startet.

echo "128 " >/proc/sys/kernel/sysrq #Den folgenden Request erlauben
echo b > /proc/sysrq-trigger        #Reboot

Obligatorische Warnung

Das die hier aufgeführten Befehle zu Datenverlust führen können erwähne ich hier nur der Vollständigkeithalber, da es eigentlich klar sein sollte

Systemd-Overrides: Anpassung von Systemdiensten mittels Drop-In

Ohne Änderung der ausgelieferten Service-Dateien
Tokk EN 495 Wörter ~3 Min.

In den Paketen vieler Programme sind systemd-Service-Dateien enthalten, damit die installierten Dienste im Hintergrund laufen oder periodisch ausgeführt werden. Ab und an kommt es aber natürlich vor, das die Dateien nicht kompatibel mit dem eigenen Setup sind und angepasst werden müssen.

So sieht die Unit-Datei für den Mattermost Server aus dem Arch-Repository zum Beispiel in Auszügen so aus:

[Unit]
Description=Mattermost Chat Server
After=mysqld.service
After=postgresql.service

[Service]
Type=simple
User=mattermost
[...]
ReadWritePaths=/etc/webapps/mattermost/config.json
[...]
ProtectSystem=strict
[...]

ProtectSystem=strict sorgt dafür, das der Prozess nur in den angegebenen ReadWritePaths lesend und schreibend zugreifen darf.1
In meinem System habe ich aber den Speicher für im Chat verschickte Anhänge auf einem gemounteten Storage liegen, da diese Daten auf Dauer den Rahmen meiner System-SSD sprengen würden. So lobenswert diese abgesicherte Standardkonfiguration auch ist, so bringt es hier natürlich auch das Problem mit sich, das Mattermost den Speicherort unter /media/store/mattermost nicht nutzen darf.

Nun kann man natürlich einfach die mitgelieferte Service-Datei anpassen und die Direktive ReadWritePath auf die eigenen Bedürfnisse anpassen, aber beim nächsten Update kann es dann zu einem der folgenden Probleme kommen: Entweder wird die Service-Datei wieder durch die aus dem Paket ersezt oder notwendige Änderungen aus dem Upstream kommen nicht am eigenen System an. Gerade bei Services die im Web exponiert sind ist letztes auch ein Sicherheitsrisiko und daher nicht empfehlenswert.

Systemd-Overrides

Die Lösung für dieses Problem bringt Systemd auch gleich mit, es ist möglich, spezielle Override-Dateien anzulegen, die dann einfach einzelne Werte aus der Originaldatei ändern ohne diese direkt zu editieren.
Der leichteste Weg führt über den Befehl systemctl edit <service> also hier im Beispiel systemctl edit mattermost.service. Es wird ein Editor geöffnet, der entweder eine neue Override-Datei erstellt oder aber eine bereits angelegte öffnet. Zusätzlich befindet sich im Editor die komplette Datei im auskommentierten Zustand, so dass man sich die Originaldatei einfach während der Bearbeitung ansehen kann.

### Editing /etc/systemd/system/mattermost.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file

[Service]
ReadWritePaths=/etc/webapps/mattermost/config.json /var/mattermost /media/store/mattermost

### Edits below this comment will be discarded


### /usr/lib/systemd/system/mattermost.service
# [Unit]
# Description=Mattermost Chat Server
# After=mysqld.service
# After=postgresql.service
[...]

In dieser Datei können nun alle Werte den Bedürfnissen des eigenen Systems angepasst werden, es muss jedoch immer auf die Sections geachtet werden. Nach dem Speichern zeigt auch systemctl status <service> entsprechend an, dass die Unit-Konfiguration mittels einer weiteren Datei erweitert wurde:

❯ sudo systemctl status mattermost
● mattermost.service - Mattermost Chat Server
    Loaded: loaded (/usr/lib/systemd/system/mattermost.service; enabled; preset: disabled)
    Drop-In: /etc/systemd/system/mattermost.service.d
             └─override.conf

die Datei /etc/systemd/system/mattermost.service.d/override.conf wurde als Drop-In geladen, beide Dateien werden gemerged und das Ergebnis wird als Konfiguration verwendet.
Änderungen an der Unit-Datei können somit ohne weiteres eingespielt werden, da diese niemals verändert wird und die notwendigen Lokalen anpassungen werden zur Laufzeit immer mit geladen. Bei Umfangreichen Änderungen kann mittels systemctl edit --full <service> auch eine komplette Kopie der Datei angelegt werden, in diesem Fall werden zukünfigte Updates natürlich höchstwahrscheinlich auch direkt immer wieder überschrieben und man ist wieder komplett selbst für den Zustand der Dienstkonfiguration verwantwortlich.