systemd-Generator
Sichere Dienste erstellen[Unit] Description=Otho worker After=network-online.target Wants=network-online.target [Service] Type=simple User=otho WorkingDirectory=/opt/otho ExecStart=/opt/otho/bin/worker Restart=on-failure RestartSec=5s NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true [Install] WantedBy=multi-user.target
Einführung
Der systemd-Generator erzeugt eine Service-Unit (eine .service-Datei) mit Härtungsoptionen, die leicht vergessen werden: ein Nicht-Root-Benutzer, NoNewPrivileges, PrivateTmp, ProtectSystem=strict und ProtectHome.
systemd lässt sich beschreiben, was ein Dienst berühren darf. Die erzeugte Unit ist ein vertretbarer Ausgangspunkt für einen Hintergrund-Worker, einen Agenten oder jeden langlaufenden Prozess.
Ziel
- Eine syntaktisch korrekte .service-Unit aus Name, Befehl, Benutzer und Arbeitsverzeichnis erzeugen.
- Basis-Härtung anwenden: dedizierter Benutzer, Neustart bei Fehler, keine neuen Privilegien, privates /tmp und schreibgeschützte Systempfade.
- Die Unit lesbar halten, damit ein Administrator sie vor dem Einsatz anpassen kann.
Eingaben
- Beschreibung (Freitext).
- ExecStart — der absolute Pfad zum ausführbaren Programm.
- Service-Benutzer — das unprivilegierte Konto, unter dem der Dienst läuft.
- Arbeitsverzeichnis (optional).
So funktioniert es
Das Werkzeug setzt drei Abschnitte zusammen. [Unit] deklariert die Beschreibung und ordnet den Dienst nach network-online.target ein. [Service] setzt Type=simple, Benutzer und Arbeitsverzeichnis, ExecStart sowie Restart=on-failure mit 5 Sekunden Verzögerung.
Es folgen Härtungsdirektiven: NoNewPrivileges=true blockiert das Erlangen neuer Privilegien über Setuid-Binaries; PrivateTmp=true gibt dem Dienst ein eigenes /tmp; ProtectSystem=strict macht das gesamte Dateisystem schreibgeschützt, ausser explizit erlaubten Pfaden; ProtectHome=true verbirgt /home, /root und /run/user.
[Install] deklariert WantedBy=multi-user.target, damit die Unit mit systemctl enable aktiviert werden kann.
Testbares Beispiel
Ausprobieren — die Analyse läuft lokal in Ihrem Browser.
Beispiel
Beschreibung: Otho worker ExecStart: /opt/otho/bin/worker Benutzer: otho Verzeichnis: /opt/otho
Erwartete Ausgabe
[Unit] Description=Otho worker After=network-online.target Wants=network-online.target [Service] Type=simple User=otho WorkingDirectory=/opt/otho ExecStart=/opt/otho/bin/worker Restart=on-failure RestartSec=5s NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true [Install] WantedBy=multi-user.target
Ausgabe verstehen
- Die Ausgabe als /etc/systemd/system/<name>.service speichern, dann sudo systemctl daemon-reload und sudo systemctl start <name> ausführen.
- Muss der Dienst in Systempfade schreiben, blockiert ProtectSystem=strict das — ReadWritePaths ergänzen oder beschreibbare Daten unter das Arbeitsverzeichnis legen.
- Die Unit ist eine Vorlage: TimeoutStartSec, Ressourcengrenzen (MemoryMax, CPUQuota) und Capabilities (CapabilityBoundingSet) an die Arbeitslast anpassen.
Risiken
- Ein Dienst als root mit Netzwerkzugriff ist die riskanteste Vorgabe; die erzeugte Unit vermeidet sie, aber prüfen Sie, dass Ihr ExecStart-Binary root gehört.
- ProtectSystem=strict kann Dienste brechen, die ausserhalb ihres Arbeitsverzeichnisses schreiben — vor Produktion testen.
- Restart=on-failure schützt nicht vor Abstürzen mit Exit-Status 0; für kritische Worker Restart=always erwägen.
Grenzen
- Das Werkzeug erzeugt die Datei; es kann nicht testen, dass Ihr Programm startet oder dass seine Rechte stimmen.
- Es erzeugt keine Socket-Aktivierung, Timer oder komplexen Abhängigkeitsgraphen.
- Die Härtung ist Basis — eine echte Prüfung sollte Capabilities, seccomp und Netzwerk-Namespaces berücksichtigen.
Offizielle Referenzen
FAQ
Warum ein eigener Benutzer für jeden Dienst?
Ein eigener unprivilegierter Benutzer begrenzt, was ein kompromittierter Dienst tun kann: Er kann weder fremde Dateien lesen noch ausserhalb seiner eigenen Pfade schreiben. Root sollte wenigen Diensten vorbehalten sein, die ihn wirklich brauchen.
Was bewirkt NoNewPrivileges=true?
Es verhindert, dass der Dienst und seine Kinder über Setuid-Binaries oder ähnliche Mechanismen Privilegien erlangen, selbst wenn solche Binaries auf dem System existieren.
Was ist ProtectSystem=strict?
Es macht das gesamte Dateisystem für den Dienst schreibgeschützt, ausser explizit erlaubten Pfaden. Es ist die stärkste ProtectSystem-Stufe und passt gut zu Diensten, die nur in ihr Arbeitsverzeichnis oder /tmp schreiben.