Dienste nicht als root ausführen
Vermeiden Sie volle Server-Kontrolle bei Sicherheitslücken. Nutzen Sie unprivilegierte User oder systemd DynamicUser zur strikten Rechtebegrenzung.
Warum nicht alles als root ausführen
Root kann auf der Maschine alles tun: jede Datei lesen, jede Einstellung ändern, das gesamte System löschen. Wenn Sie einen Dienst als root ausführen, übertragen Sie die gesamte Macht auf diesen Dienst. Wenn der Dienst einen Fehler aufweist, den ein Angreifer ausnutzen kann, erhält dieser nicht nur Zugriff auf den Dienst, sondern auf root, und root bedeutet den gesamten Server. Die Ausführung als unprivilegierter Benutzer begrenzt den Schaden. Ein Fehler in einem Dienst, der unter einem eingeschränkten Konto läuft, gibt einem Angreifer nur das, worauf dieses Konto Zugriff hat, was fast nichts sein sollte.
Dies ist das Prinzip der minimalen Rechtevergabe (Principle of Least Privilege): Geben Sie jedem Teil des Systems genau den Zugriff, den es zur Erfüllung seiner Aufgabe benötigt, und nicht mehr. Dies ist die effektivste Methode, um den Schadensradius einer Kompromittierung zu begrenzen, und auf einem modernen Server kostet die Umsetzung fast nichts.
Ein dedizierter Account pro Dienst
Der klassische Ansatz besteht darin, für jeden Dienst einen separaten Systembenutzer zu erstellen, der nur die Dateien des jeweiligen Dienstes besitzt und sich nicht einloggen kann. Ein Systemkonto für eine Web-App könnte so aussehen:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvcJedes Flag ist wichtig. --system macht es zu einem Service-Account statt zu einem Benutzerkonto für Menschen. --no-create-home überspringt ein Home-Verzeichnis, das nicht benötigt wird. --shell /usr/sbin/nologin bedeutet, dass ein Angreifer selbst dann keine Shell öffnen kann, wenn er das Konto irgendwie erlangt. Das Konto existiert nur, um einen Prozess und dessen Dateien zu besitzen.
Geben Sie diesem Benutzer dann nur die Dateien, die er benötigt, und nicht mehr:
sudo chown -R appsvc:appsvc /opt/myappNun liest und schreibt der Dienst in seinem eigenen Verzeichnis und hat keine Berechtigung für andere Bereiche auf der Festplatte. Falls der Dienst ausgenutzt wird, sind die Dateien, die der Angreifer ändern kann, auf /opt/myapp beschränkt; das Konto kann weiterhin alles lesen, was für alle lesbar ist, aber es kann den Rest des Systems nicht modifizieren.
Lassen Sie systemd den Dienst als diesen Benutzer ausführen
Sobald das Konto existiert, weisen Sie systemd an, den Dienst als diesen Benutzer auszuführen. In der Unit-Datei erledigt dies eine Zeile:
[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvcUser=appsvc bedeutet, dass der Prozess mit den eingeschränkten Privilegien des Kontos statt mit den Privilegien von root startet. Dies ist der normale, bewährte Weg, um eine Anwendung unter systemd auszuführen, und es lohnt sich, dies für jeden Dienst zu tun, für den Sie eine Unit schreiben.
Oder überspringen Sie den Account vollständig mit DynamicUser
systemd kann noch einen Schritt weiter gehen und einen temporären Benutzer für Sie erstellen, der nur existiert, solange der Dienst läuft. Setzen Sie DynamicUser=yes, und Sie müssen kein Konto mehr verwalten:
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myappBeim Start weist systemd eine ungenutzte User-ID zu; beim Stopp wird sie freigegeben. Der Dienst erhält außerdem ein privates /tmp, eine schreibgeschützte Ansicht der meisten Dateisystembereiche, und ein beschreibbares State-Verzeichnis unter /var/lib/myapp, das StateDirectory= einrichtet und bereitstellt. Für einen eigenständigen Dienst, der nur sein eigenes State-Verzeichnis benötigt, ist DynamicUser=yes der einfachste Weg für eine starke Isolation, da es überhaupt kein dauerhaft existierendes Konto gibt, das ein Angreifer angreifen könnte.
Das manuelle Schreiben von Units ist mühsam, und die korrekte Verwendung der Hardening-Direktiven bietet den größten Nutzen. Der Generator in dem systemd Service und Timer Guide kann diese Optionen für Sie ausfüllen, damit die Unit beim ersten Mal korrekt ist.
Wie dies mit dem Rest zusammenpasst
Die minimale Rechtevergabe ist eine Ebene und arbeitet mit den anderen Ebenen zusammen, anstatt sie zu ersetzen. Eine Default-Deny-Firewall kontrolliert, was den Dienst erreichen kann; die Ausführung als unprivilegierter Benutzer kontrolliert, was der Dienst tun kann, wenn er kompromittiert wird; und Hardened SSH hält Angreifer von der Maschine fern. Keine dieser Maßnahmen allein ist ausreichend, aber zusammen bedeutet es, dass ein Fehler in einem Dienst nicht zur Kompromittierung des gesamten Servers führt.
Bevor Sie fortfahren, gehen Sie eine Hardening-Checkliste für die gesamte Maschine durch und erstellen Sie eine personalisierte Kopie zum Abarbeiten:
FAQ
Warum sollte ich einen Dienst nicht als root ausführen?
Weil root alles auf der Maschine tun kann. Ein Dienst, der als root läuft und ausgenutzt wird, übergibt dem Angreifer den gesamten Server, nicht nur den Dienst. Führen Sie den Dienst als eingeschränktes, unprivilegiertes Konto aus. Reservieren Sie root für die Administration und führen Sie jeden dauerhaft laufenden Dienst als eingeschränkten Benutzer aus.
Wie erstelle ich einen Benutzer, der sich nicht einloggen kann?
Führen Sie sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME aus. Die nologin Shell bedeutet, dass das Konto keine interaktive Sitzung öffnen kann, selbst wenn die Anmeldedaten gestohlen werden; --system markiert es als Service-Account, und --no-create-home überspringt ein nicht benötigtes Home-Verzeichnis. Geben Sie ihm mit chown nur die Inhaberschaft an seinen eigenen Dateien.
Was ist systemd DynamicUser?
DynamicUser=yes weist systemd an, einen temporären Benutzer für den Dienst zu erstellen, der nur während dessen Laufzeit existiert, sodass Sie kein dauerhaftes Konto verwalten müssen. Es gibt dem Dienst außerdem ein privates /tmp, eine weitgehend schreibgeschützte Dateisystem-Ansicht, und ein verwaltetes State-Verzeichnis. Es ist der einfachste Weg, einen eigenständigen Dienst unter einer temporären Identität mit geringen Privilegien auszuführen.
Ersetzt die Ausführung als Non-Root-Benutzer eine Firewall?
Nein. Sie schützen unterschiedliche Dinge. Die Ausführung als unprivilegierter Benutzer begrenzt, was ein Dienst tun kann, wenn er kompromittiert wird, während eine Firewall begrenzt, was den Dienst überhaupt erreichen kann. Verwenden Sie beides zusammen mit Hardened SSH, damit jede Ebene das abdeckt, was die anderen nicht abdecken können.
Welche Dateien sollte der Dienst-Benutzer besitzen?
Nur die Dateien, die der Dienst tatsächlich benötigt, und nicht mehr. Geben Sie dem Konto die Inhaberschaft an seinem eigenen Arbeitsverzeichnis und seinen Daten und lassen Sie alles andere im Besitz von root. Ein gutes Muster ist sudo chown -R svc-app:svc-app /opt/svc-app für das Anwendungsverzeichnis, während die Konfiguration unter /etc im Besitz von root bleibt und nur vom Dienst gelesen werden kann. Das Ziel ist, dass im Falle einer Kompromittierung des Prozesses die Dateien, die er ändern kann, auf seine eigenen Daten beschränkt sind und nicht auf den Rest des Systems.