Fundierte Artikel über Technologien, die das Kommende formen.

Die Evolution von sudo: Von Unix su zu modernen Privilegien

Die Geschichte von sudo: von Unix su bis zu doas, polkit und run0. Sicherheitsfallen und bewährte Praktiken für Linux-Admins im Überblick.

Eine Reihe Schlüssel von verrostetem Eisen bis zu schlankem Modernen, auf einer Samtwand ausgestellt

Hier ist eine Tatsache, die die meisten überrascht: Wenn du dein Passwort in sudo eingibst, siehst du überhaupt keine Rückmeldung. Keine Sternchen, keine Punkte, nichts. Der Cursor steht einfach still. Diese Designentscheidung fiel in den 1980er-Jahren und verwirrt Nutzer seitdem über vier Jahrzehnte. Viele glauben, ihr Terminal sei eingefroren, tippen das Passwort mehrmals ein oder vermuten, dass irgendetwas kaputt ist. Ubuntu hat sich schließlich entschieden, standardmäßig Sternchen anzuzeigen – und beendet damit eine 46 Jahre alte Tradition der stillen Passworteingabe.

Diese kleine Änderung zeigt etwas Größeres: Wie Linux die Rechteerweiterung handhabt, ist ein Flickenteppich aus Entscheidungen über Jahrzehnte – manche brillant, manche mehr als fragwürdig, alle mit dem Gewicht der Abwärtskompatibilität. Wer versteht, wie wir hierher gekommen sind, trifft heute bessere Sicherheitsentscheidungen.

Vor sudo: Die Welt von su

Das ursprüngliche Werkzeug für die Rechteerweiterung unter Unix war su – „substitute user“. Es tat genau eine Sache: Es wechselte die gesamte Shell-Sitzung zu einem anderen Benutzer, typischerweise root. Man tippte su, gab das Passwort von root ein, erledigte die Adminarbeit und meldete sich dann wieder am normalen Konto ab.

$ su
Password: [type root's password]
# whoami
root
# apt install nginx
# exit
$ whoami
normaluser

Die Probleme mit su wurden offensichtlich, als Unix-Systeme über eine Handvoll vertrauenswürdiger Operatoren hinauswuchsen. Jeder, der Adminzugriff brauchte, musste das root-Passwort kennen. Verließ jemand das Team, musste man das root-Passwort ändern und das neue an alle anderen verteilen. Es gab keine Audit-Spur – sobald jemand root war, wurden alle Aktionen als „root“ protokolliert, ohne Nachweis, wer was tatsächlich ausgeführt hatte. Und su gab eine vollwertige Root-Shell, was bedeutete, dass ein einziger Tippfehler das System zerstören konnte.

Die klassische Horrorgeschichte: Ein Admin wollte rm -rf /tmp/old_files tippen, drückte aber versehentlich Enter nach rm -rf /. Mit einer vollwertigen Root-Shell hindert nichts diesen Befehl an der Ausführung. su machte keinen Unterschied zwischen „Diese Person muss nginx neu starten“ und „Diese Person braucht uneingeschränkten Zugriff auf das gesamte System“.

Wie sudo das Root-Passwort-Problem löste

sudo („superuser do“) wurde 1980 an der SUNY Buffalo von Bob Coggeshall und Cliff Spencer entwickelt. Die Kerneinsicht war einfach, aber wirkungsvoll: Statt das root-Passwort zu teilen, lässt man einzelne Benutzer bestimmte Befehle als root ausführen – und zwar mit dem eigenen Passwort. Der Systemadministrator legt in einer Konfigurationsdatei fest, wer was ausführen darf.

Das löste mehrere Probleme auf einmal:

  • Kein gemeinsames root-Passwort. Jeder Benutzer meldet sich mit den eigenen Zugangsdaten an. Verlässt jemand das Team, entziehst du ihm einfach den sudo-Zugang. Eine Passwortrotation ist nicht nötig.
  • Feingranulare Berechtigungen. Du kannst einem Entwickler erlauben, einen bestimmten Dienst neu zu starten, ohne ihm vollen root-Zugriff zu geben.
  • Audit-Spur. Jeder sudo-Befehl wird mit dem Benutzernamen, dem ausgeführten Befehl und dem Zeitpunkt protokolliert.
  • Zeitlich begrenzte Rechteerweiterung. Statt einer offenen Root-Shell führt sudo einen einzelnen Befehl mit erhöhten Rechten aus und fällt danach wieder auf den normalen Modus zurück.
# Run a single command as root
$ sudo apt install nginx
[sudo] password for priya:
# That's YOUR password, not root's
# The audit trail in /var/log/auth.log:
# Mar 20 14:23:01 web-03 sudo: priya : TTY=pts/0 ;
#   PWD=/home/priya ; USER=root ; COMMAND=/usr/bin/apt install nginx

Die sudoers-Datei: mächtig und gefährlich

Die Konfiguration von sudo liegt in /etc/sudoers, und deren Syntax gehört zu den verwirrendsten Dingen in der Linux-Administration. Ein einziger Syntaxfehler kann dich komplett von sudo aussperren. Deshalb gibt es den Befehl visudo – er prüft die Datei, bevor sie gespeichert wird.

# /etc/sudoers syntax:
# WHO  WHERE = (AS_WHOM) WHAT
# Let priya run anything as root on any host
priya ALL=(ALL:ALL) ALL
# Let the 'webdev' group restart nginx only
%webdev ALL=(root) /usr/bin/systemctl restart nginx,\
/usr/bin/systemctl reload nginx
# Let deploy user run deploys without a password
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh
# DANGEROUS: This looks restrictive but isn't
bob ALL=(root) /usr/bin/vim
# Bob can now run: sudo vim, then :!bash to get a root shell

Das letzte Beispiel – jemandem sudo-Zugriff auf vim zu geben – ist eine Sicherheitsfalle, in die Leute ständig tappen. Vim (und viele andere Programme) können Shell-Befehle starten. Kann ein Benutzer sudo vim ausführen, hat er faktisch uneingeschränkten root-Zugriff. Dasselbe gilt für less, man, awk, find, python und Dutzende weitere Befehle. Das GTFOBins-Projekt pflegt eine umfassende Liste von Binärdateien, mit denen sich eingeschränkte Shells umgehen lassen.

Eigenheiten und Sicherheitsfallen von sudo

sudo hat in seiner über 40-jährigen Geschichte einiges recht seltsames Verhalten angesammelt. Diese Eigenheiten zu verstehen ist wichtig für die Sicherheit:

  • Credential-Caching. Nachdem du dein Passwort eingegeben hast, merkt sich sudo es standardmäßig für 15 Minuten. In diesem Zeitfenster läuft jeder sudo-Befehl ohne Authentifizierung. Wenn du ein entsperrtes Terminal unbeaufsichtigt lässt, kann jeder bis zu 15 Minuten lang sudo-Befehle ausführen. Mit sudo -k leerst du den Cache sofort.
  • Die Einstellung tty_tickets. Standardmäßig ist der Credential-Cache von sudo pro Terminal getrennt. Auf manchen Systemen entsperrt die Authentifizierung in einer Terminal-Sitzung aber sudo in allen. Prüfe deine Defaults-Einstellungen.
  • Umgebungsvariablen. sudo bereinigt die meisten Umgebungsvariablen, aber nicht alle. LD_PRELOAD und LD_LIBRARY_PATH werden entfernt, doch bei falsch konfiguriertem env_keep kann ein Angreifer schädliche Bibliothekspfade einschleusen. Darauf basieren mehrere reale Exploits zur Rechteerweiterung.
  • Die NOPASSWD-Falle. NOPASSWD ist für Automatisierung praktisch, aber gefährlich, wenn es zu breit eingesetzt wird. Eine kompromittierte Anwendung, die als Benutzer mit NOPASSWD-sudo-Zugriff läuft, hat faktisch root – es gibt kein Passwort, das man knacken müsste.
# Security hardening for sudoers:
# Require password every time (disable caching)
Defaults timestamp_timeout=0
# Or reduce cache to 1 minute
Defaults timestamp_timeout=1
# Ensure credential cache is per-terminal
Defaults tty_tickets
# Log all sudo I/O (records full terminal sessions)
Defaults log_input, log_output
Defaults iolog_dir=/var/log/sudo-io
# Require root password instead of user password
# (prevents compromised user accounts from sudo-ing)
Defaults rootpw
# Show asterisks when typing password
Defaults pwfeedback

Moderne Alternativen: doas, polkit und run0

Die Komplexität von sudo hat mehrere Alternativen hervorgebracht, die jeweils eine eigene Philosophie verfolgen.

doas: sudo ohne die Komplexität

doas von OpenBSD („dedicated OpenBSD application subexecutor“) wurde 2015 von Ted Unangst entwickelt, und zwar gezielt, weil sudo zu komplex geworden war, um es noch vernünftig prüfen zu können. Die gesamte Konfiguration umfasst typischerweise 2–3 Zeilen:

# /etc/doas.conf — the entire configuration
permit persist priya
permit nopass deploy as root cmd /opt/deploy/run.sh
# That's it. Compare this to a typical sudoers file.
# 'persist' is like sudo's credential caching
# 'nopass' is like NOPASSWD

Der Quellcode von doas umfasst rund 2.500 Zeilen C. Der von sudo hat über 150.000. Für Systeme, die du nicht mit den erweiterten Funktionen von sudo brauchst (etwa dem Abgleich von Argumenten pro Befehl oder der LDAP-Integration), ist doas deutlich einfacher zu konfigurieren, zu prüfen und abzusichern. Ich nutze es auf meinen privaten Servern seit Jahren und habe sudo kein einziges Mal vermisst.

polkit: feingranulare Desktop-Berechtigungen

PolicyKit (polkit) verfolgt einen völlig anderen Ansatz. Statt einzelne Befehle zu umhüllen, definiert es Aktionen, die Anwendungen anfordern können. Braucht eine Desktop-App Änderungen an den Netzwerkeinstellungen, fragt sie polkit nach der Erlaubnis, und polkit entscheidet anhand seiner Regeln, ob es gewährt, verweigert oder den Nutzer zur Bestätigung auffordert.

So kannst du unter Linux auf dem Desktop einen USB-Stick ohne Passwort einbinden, während für die Installation von Software eine Authentifizierung nötig ist. Die Granularität liegt auf der Ebene der Aktion, nicht des Befehls, was besser dazu passt, wie Desktop-Nutzer über Berechtigungen denken.

run0: Systemds radikale Neuerfindung

run0 von systemd ist der jüngste Neuzugang und funktioniert grundlegend anders als sudo. Statt einen Befehl als root aus deiner bestehenden Sitzung heraus auszuführen (was setuid-Bits erfordert und Sicherheitsprobleme mit sich bringt), bittet run0 den Dienstmanager, einen neuen Dienst zu starten, der als root läuft. Deine Benutzersitzung erhält nie erhöhte Rechte – der privilegierte Prozess ist vollständig getrennt.

Das umgeht ganze Kategorien von sudo-Schwachstellen. Es gibt kein setuid-Binary, kein Credential-Caching und keine Angriffsfläche durch Umgebungsvariablen. Der Nachteil: run0 setzt systemd voraus, was es für BSD-Systeme und minimale Linux-Installationen ungeeignet macht. Auf systemd-basierten Servern ist es aber wohl die sicherste verfügbare Option.

Praktische Empfehlungen

Nach Jahren der Verwaltung von Linux-Servern und der Untersuchung von Vorfällen mit Rechteerweiterung empfehle ich Folgendes:

  1. Root-Login vollständig deaktivieren. Verwende für alles sudo oder doas. Ein gemeinsames root-Passwort sollte es nicht geben.
  2. In der sudoers-Datei Gruppen statt einzelner Benutzer verwenden. Verwalte Zugriffe über Gruppenmitgliedschaften. Verlässt jemand das Team, entfernst du ihn aus der Gruppe.
  3. Niemals sudo-Zugriff auf Interpreter oder Editoren geben. Kein sudo vim, sudo python, sudo less. Wenn du eine root-eigene Datei bearbeiten musst, nutze stattdessen sudoedit.
  4. NOPASSWD-Regeln auf ein Minimum beschränken. Setze sie nur für automatisierte Prozesse ein, und nur für bestimmte Befehle mit vollständigen Pfaden.
  5. sudo-Protokollierung aktivieren. Protokolliere mindestens alle sudo-Befehle. Für sensible Systeme aktiviere die vollständige I/O-Protokollierung.
  6. Für einfachere Systeme doas in Betracht ziehen. Wenn du keine LDAP-Integration oder komplexen Abgleichregeln brauchst, ist doas leichter richtig zu konfigurieren.
  7. Credential-Caches konsequent verkürzen. Setze timestamp_timeout auf 1–5 Minuten oder deaktiviere das Caching auf Produktivservern ganz.

Der beste Mechanismus zur Rechteerweiterung ist der, der genau den nötigen Zugriff gewährt, für genau die nötige Zeit, mit einer lückenlosen Audit-Spur. Alles andere ist ein Kompromiss.

sudo verschwindet so schnell nicht. Es ist zu tief in Skripten, Automatisierung, Dokumentation und Muskelgedächtnis verankert. Doch die Landschaft der Alternativen ist gesünder als je zuvor. Ob du bei sudo bleibst (richtig abgesichert), auf doas wechselst (wegen der Einfachheit) oder run0 einsetzt (für sicherheitskritische Systeme) – wichtig ist, zu verstehen, was dein Werkzeug zur Rechteerweiterung wirklich tut. Denn die Lücke zwischen dem, was Menschen glauben, dass sudo tut, und dem, was es tatsächlich tut, ist der Ort, an dem die meisten Sicherheitsvorfälle entstehen.