Hier habe ich einen guten Artikel entdeckt, der beschreibt, welche Möglichkeiten alles Systemd bietet, um Prozesse einzuschränken: Flash Systems – Systemhärtung mit systemd.
Aus meiner Sicht sind folgende Optionen erstrebenswert, aber nicht bei allen
Diensten lässt sich der Gurt so festzurren. Weil ich meine Systeme mit einem
Read-only-Root betreibe (das bereits
ProtectSystem=full
entspricht) und die Dateisystemzugriffe über AppArmor
begrenze, wären viele Optionen nicht notwendig, aber bisher sind mir noch keine
Nachteile der Doppelung aufgefallen.
[Service]
CapabilityBoundingSet=
LockPersonality=true
MemoryDenyWriteExecute=true
NoNewPrivileges=true
PrivateDevices=true
PrivateTmp=true
ProtectClock=true
ProtectControlGroups=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
# strict: mounts the whole system read-only
# full: mount only /var as read-write
# true: mount /var and /etc as read-write
ProtectSystem=strict
# Make some paths writable
#ReadWritePaths=/…
ProtectHome=true
# Make sure that the process can only see PIDs and process details of itself,
# and the second option disables seeing details of things like system load and
# I/O etc
ProtectProc=invisible
ProcSubset=pid
RemoveIPC=true
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources @obsolete
# No network at all
#SystemCallFilter=~@network-io
Die Qualität der Einstellungen lässt sich mit systemd-analyze
security ….service
prüfen.
Für User-Units lassen sich nur diese Optionen nutzen:
[Service]
LockPersonality=true
NoNewPrivileges=true
MemoryDenyWriteExecute=true
RemoveIPC=true
RestrictAddressFamilies=AF_INET AF_INET6
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
Rechte zur Nutzung von strace
Viele Programme geben im Fehlerfall keine aussagekräftigen Meldungen aus. Daher
ist es oft hilfreich, dem Prozess mit strace zuzuschauen. Hierfür muss man
folgende Einstellungen tätigen und natürlich ExecStart=/usr/bin/strace -AfvttTy
-o /tmp/%p.st …
setzen:
CapabilityBoundingSet=CAP_SYS_PTRACE
ReadWritePaths=/tmp
PrivateTmp=no
SystemCallFilter=@debug @privileged
Ermitteln der Lockerungen
Leider habe ich für die Einstellungen noch keinen Complain-Mode wie bei
AppArmor gefunden. Daher gehe ich immer nach dem Ausschlussprinzip durch die
obigen Einstellungen und schaue, welche für das Scheitern des Prozesses
verantwortlich ist. Zuerst nehme ich immer CapabilityBoundingSet
und
SystemCallFilter
raus und suche die Einstellungen, damit es funktioniert.
Danach suche ich mit strace nach den Funktionen, die bei SystemCallFilter
erlaubt werden müssen; der Befehl systemd-analyze syscall-filter
gibt die
vorhandenen Gruppen aus. Anhand derer ist meist auch zu erkennen, welche Rechte
bei CapabilityBoundingSet
notwendig sind; die Liste ist in
capabilities(7)
erklärt. Die Capabilities lassen sich auch leichter mit AppArmor und complain
ermitteln.
- SUID-Programme (wie Exim, mount, procmail oder passwd) benötigen
NoNewPrivileges=no
für den Benutzerwechsel - für Syslog ist
RestrictAddressFamilies=AF_UNIX
notwendig, sonst kann auch dieses Recht entzogen werden - Interpreter wie Node und Python benötigen
MemoryDenyWriteExecute=no
- Prozesse, die unter /var schreiben wollen, benötigen
ProtectSystem=full