Wird das sudo-Passwort im Klartext gesendet?
Nicht über das Netz. Alles in einer SSH-Sitzung ist verschlüsselt, auch was Sie an einer sudo-Abfrage tippen. Das Passwort wird auf dem Server entschlüsselt, wie es sein muss, damit sudo es prüfen kann, ein kompromittierter Server kann es also abgreifen. Das ist ein Grund, dieses Passwort nirgendwo sonst wiederzuverwenden.
Der normale Weg: ssh -t
sudo braucht ein Terminal, um nach einem Passwort zu fragen, und ein Befehl aus der Ferne bekommt standardmäßig keines:
$ ssh user@server 'sudo whoami'
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: a password is required
Die Fehlermeldung schlägt -S vor, und hier gehen die Leute in die falsche Richtung. Die einfache Lösung ist -t, das ein Terminal anfordert:
ssh -t user@server 'sudo whoami'
Sie bekommen die normale Abfrage, nichts wird angezeigt und nichts landet in einer Befehlszeile.
Was bei sudo -S verraten wird
Dieses Muster sollten Sie vermeiden:
ssh user@server 'echo mypassword | sudo -S systemctl restart myapp'
Das Passwort ist jetzt Teil eines Befehls und taucht deshalb an drei Stellen auf:
- In der Prozessliste auf dem Server. Während der Befehl lief, sah ein anderes unprivilegiertes Konto auf dem Testserver mit einfachem
psdies:user bash -c echo mypassword | sudo -S -p "" sleep 3. - In der Prozessliste auf Ihrem Rechner. Der ganze Text ist ein Argument von
ssh, daher zeigtpsihn auch dort. - In Ihrer lokalen Shell-History, wenn Sie ihn getippt haben, und in jedem Skript oder CI-Log, das ihn enthält.
Wenn Sie sudo wirklich aus einem Skript füttern müssen
Lesen Sie das Passwort ohne Anzeige ein und senden Sie es über die Standardeingabe, damit es nie zum Argument wird:
read -rs SUDO_PW
printf '%s\n' "$SUDO_PW" | ssh user@server 'sudo -S -p "" whoami'
unset SUDO_PW
printf ist ein Shell-Builtin und startet deshalb keinen Prozess, den ps zeigen kann. Im selben Test sah das andere Konto nur sudo -S -p sleep 3. -p "" entfernt die Abfrage aus der Ausgabe. sudo verwendet hier die Standardeingabe für das Passwort, der Befehl auf dem Server sollte also keine eigene Eingabe brauchen.
Für Automatisierung: NOPASSWD für genau einen Befehl
Ein Skript sollte gar kein Passwort halten. Erlauben Sie nur, was es braucht:
# /tmp/deploy.sudoers
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/journalctl -u myapp -n 100 --no-pager
Prüfen Sie die Datei vor der Installation, denn eine kaputte sudoers-Datei kann Sie von sudo aussperren:
sudo visudo -cf /tmp/deploy.sudoers
sudo install -m 0440 -o root -g root /tmp/deploy.sudoers /etc/sudoers.d/deploy
sudo visudo -c
Verwenden Sie sie dann mit -n, damit eine Abweichung sofort scheitert und nicht hängt, während sie auf ein Passwort wartet:
$ ssh deploy@server 'sudo -n /usr/bin/systemctl restart myapp'
$ ssh deploy@server 'sudo -n /usr/bin/systemctl stop myapp'
sudo: a password is required
Was ein Konto ausführen darf, zeigt sudo -l. Vier Fallen:
- Ein Befehl ohne Argumente in der Regel erlaubt beliebige Argumente. Mit nur
/usr/bin/idin der Regel liefen in unserem Test sowohlsudo -n /usr/bin/idals auchsudo -n /usr/bin/id -u. Schreiben Sie die Argumente hin, die Sie meinen. - Dateinamen mit einem Punkt werden ignoriert.
/etc/sudoers.d/deploy.confhatte in unserem Test keine Wirkung, dieselbe Datei mit dem Namendeployfunktionierte. - Manche Befehle können eine Shell starten. Editoren, Pager,
find -execundtarkönnen andere Programme als root ausführen, sodass die Erlaubnis für einen davon einer Erlaubnis für alles gleichkommen kann. Deshalb hat die Regel oben--no-pager: Ohne es kann journalctl einen Pager öffnen. - Platzhalter passen auch auf Leerzeichen. Das sudoers-Handbuch warnt, dass Platzhalter in Argumenten auf jedes Zeichen passen, auch auf Leerraum, sie können also mehr Argumente treffen, als Sie geplant haben.
Wie lange sudo sich an Sie erinnert
Standardmäßig fragt sudo 5 Minuten lang nicht erneut, und die Aufzeichnung gilt getrennt für jedes Terminal. Im Test führte eine ssh -t-Sitzung ein zweites sudo -n whoami ohne Abfrage aus. Um das vorzeitig zu beenden, führen Sie sudo -k aus. Damit für ein Konto jedes Mal gefragt wird, fügen Sie dies mit visudo hinzu:
Defaults:deploy timestamp_timeout=0
Eine offen gelassene Root-Shell ist der Ort der meisten Fehlgriffe. Siehe Fehler auf Produktionsservern vermeiden.
sudo -A und askpass
Mit -A führt sudo das in SUDO_ASKPASS genannte Programm aus und liest das Passwort aus dessen Ausgabe:
SUDO_ASKPASS=$HOME/bin/askpass sudo -A whoami
Das hält das Passwort aus der Prozessliste heraus, aber der Helfer muss es irgendwoher bekommen. Auf einem Server ohne grafische Sitzung bedeutet das meist eine Datei, wie in unserem Test, das Geheimnis liegt dann auf der Platte. Eine enge NOPASSWD-Regel ist normalerweise die bessere Antwort.
Ansible
Verwenden Sie --ask-become-pass (-K), um abgefragt zu werden, oder halten Sie ansible_become_password in einer mit Ansible Vault verschlüsselten Datei. Übergeben Sie es nicht mit -e auf der Befehlszeile, denn das legt es wie jedes andere Argument in die Prozessliste und Ihre History.
Eine NOPASSWD-Regel für einige Befehle funktioniert mit Ansible nicht. Laut Dokumentation lässt sich die Rechteerweiterung nicht auf bestimmte Befehle beschränken, weil Module aus einer temporären Datei laufen, deren Name sich jedes Mal ändert. Sie empfiehlt, ein getrenntes Konto ohne diese Einschränkung zu verwenden.
Fragen
Wird das sudo-Passwort über SSH im Klartext gesendet?
Nein. Alles in einer SSH-Sitzung ist verschlüsselt, auch was Sie an der sudo-Abfrage tippen. Entschlüsselt wird es auf dem Server, der es prüfen muss.
Warum meldet ssh, dass ein Terminal zum Lesen des Passworts nötig ist?
Ein entfernter Befehl bekommt standardmäßig kein Terminal, sudo braucht aber eins für die Passwortabfrage. Ergänzen Sie -t, etwa ssh -t user@server 'sudo command'.
Ist NOPASSWD für Skripte sicher?
Sicherer als ein gespeichertes Passwort, wenn die Regel genau einen Befehl mit seinen Argumenten nennt. Meiden Sie Editoren, Pager und andere Programme, die eine Shell starten können.
Quellen
- Handbuch sudo(8)
- Handbuch sudoers(5)
- Handbuch visudo(8)
- Understanding privilege escalation, Ansible-Dokumentation