Eigentlich ist es ganz simpel: Du schreibst ein Script. Und in diesem Script
willst du irgendetwas am System erledigen und benötigst besondere
Zugriffsrechte. Und dafür gibt es ja sudo
. Also schreibst du in dein Script
sudo ...
Arg! Nein! Nicht machen!!! Ende des Artikels.
Okay, okay. Da die Konstruktion immer wieder vorkommt, scheint es angebracht, ein paar Zeilen zu dem Thema zu verlieren. Zur Veranschaulichung des Problems werfen wir einen Blick in ein Nagios-Plugin für pfSense. Aufgabe des Plugins ist es, auf Updates zu prüfen und zu alarmieren, wenn ein solches vorliegt. Und hier der entsprechende Code 1:
if (file_exists("{$g['varrun_path']}/pkg.dirty")) {
$system_pkg_version = get_system_pkg_version(false,false);
} else {
shell_exec("sudo touch "."{$g['varrun_path']}/pkg.dirty");
$system_pkg_version = get_system_pkg_version(false,false);
shell_exec("sudo rm " . "{$g['varrun_path']}/pkg.dirty");
}
Jaja, Qualität und Style von Monitoring-Code hatten wir bereits im letzten
Artikel. Das nehmen wir diesmal als
gegeben hin und betrachten einzig und allein den sudo
-Teil. Obiger Code wird
von einem Monitoring-Agenten auf dem zu überwachenden System ausgeführt. Der
Agent sollte aus Sicherheitsgründen nicht als Root-User ausgeführt werden, da
wir dem Monitoring keinen Vollzugriff auf das zu überwachende System einräumen
wollen. Lassen wir das Script ohne weitere Anpassungen laufen, bekommen wir im
besten Fall eine Fehlermeldung folgender Sorte:
sudo: command not found
Im schlechteren Fall:
Sorry, try again.
Sorry, try again.
sudo: 3 incorrect password attempts
Und im schlechtesten Fall:
[sudo] password for root:
Sudo ist eine externe Abhängigkeit des Scripts. Und nur, weil jedes Ubuntu das
Sudo-Paket standardmäßig mitbringt, bedeutet das noch lange nicht, dass unter
jeder Linux- oder Unix-Umgebung sudo
als Kommando bereitsteht. Und selbst
wenn es das tut, gewährt Sudo zusätzliche Berechtigungen für einen
unprivilegierten User und muss diesen Zugriff entsprechend absichern. Ein
Monitoring-Script läuft aber nicht aus einer interaktiven Shell heraus und kann
daher auch keine Eingaben, beispielsweise einer Passwort-Abfrage,
entgegennehmen. Um ein Script mit einer solchen Sudo-Konstruktion überhaupt in
einer nicht-interaktiven Umgebung ausführen zu können, muss in die Sudo-Config
gegriffen, die Vergabe zusätzlicher Berechtigungen durch Sudo ohne Passwort
erlaubt und damit die Sicherheit des Systems insgesamt gesenkt werden.
Aber selbst wenn wir die Konfiguration von Sudo entsprechend anpassen, welche Sudo-Regel setzen wir? Die möglichen Optionen klingen allesamt nicht wirklich verlockend:
sudo touch
und sudo rm
. Äh,
rm, ja, ne…varrun_path
gesetzt wird, welche sich dynamisch ändern kann und die wir in
der Sudo-Config trotzdem hart coden müssten), verletzen damit das
DRY-Prinzip
und rennen dann bei etwaigen Updates des Plugins obskuren Fehlerszenarien hinterher.Und bei all dem Durcheinander, welches eine solche Konstruktion bis hierhin schon angerichtet hat, dieses DevOps-Desaster birgt noch einen weiteren Aspekt: Um Sudo aus einem Script heraus überhaupt zu ermöglichen, muss das aufrufende Script einen Shell-Call ausführen. Es muss also den eigenen Kontext verlassen und einen weiteren Prozess starten. In diesem Beispiel, um ganz banal eine Datei zu touchen und anschließend zu löschen; beides Operationen, die sich deutlich besser mit den Bordmitteln von PHP und damit im Kontext des eigentlichen Programm-Codes abbilden lassen würden. In deutlich drastischer Konsequenz zeigt sich das an folgendem Code-Beispiel aus einem weiteren Monitoring-Plugin 2:
@state = `sudo zpool status #{name} | grep '^ state: ' | cut -d ' ' -f 3`.strip
@capacity = `sudo zpool get -H capacity #{@name} | awk '{print $3}' | cut -d '%' -f1`.strip.to_i
Okay, das alles muss irgendwie anders gehen. Und für einen anderen Ansatz legen wir Sudo erst einmal zurück in die Werkzeugkiste. Sudo ist ein Tool, um auf interaktiven Shells zusätzliche Berechtigungen für die Ausführung von Befehlen zu erhalten und nicht für Rechtemanagement innerhalb von Scripten gedacht.
Unix, und Linux im Besonderen, kennt Berechtigungen und bringt diverse Konzepte
mit, um den Zugriff auf Ressourcen zu verwalten. So gibt es neben Benutzern
auch Gruppen. Für den hier aufgezeigten Fall wäre es denkbar, eine Gruppe für
das Repo-Management anzulegen, die benötigten Ressourcen für den Zugriff durch
die Gruppe freizugeben und den Monitoring-Agenten in diese Gruppe aufzunehmen.
Für komplexere Setups bieten sich Access Control
Lists an. Auch eine
Entkoppelung durch Service-Architekturen, APIs oder
Interprozesskommunikation
ist denkbar. In jedem Fall aber möchte ich als Admin des Systems die Wahl
haben, wie ich den Zugriff auf die benötigten Ressourcen einräume, und nicht
vor ein hart eingebautes sudo
gestellt werden, welches mir meine eigenen
Werkzeuge aus der Hand nimmt und dafür das falsche Tool zurück reicht. Das ist
schlicht und ergreifend “not your department”!
Und überhaupt, was ist da eigentlich grundsätzlich schiefgelaufen, dass die Abfrage der Version einer Software das zugrundeliegende Software-Repository als dirty flaggen muss? Warum ist eine reine Abfrage eines Zustands nicht frei von Seiteneffekten?
Content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Created with Solid template by TemplateMag
Proudly powered by Pelican, which takes great advantage of Python.