fix(PROJ-68): CapabilityBoundingSet blockiert sudo trotz korrekter sudoers-Regel

QA-Re-Diagnose auf 132 fand einen zweiten, unabhängigen Blocker: die
archivmail.service-Unit setzt CapabilityBoundingSet=CAP_NET_BIND_SERVICE
CAP_NET_ADMIN. Das kappt das Capability-Set des GESAMTEN Prozessbaums
inklusive der von exec.Command("sudo", ...) geforkten Kindprozesse - sudo
braucht aber zusaetzlich CAP_SETUID/CAP_SETGID um auf uid/gid 0 zu
wechseln, sonst bricht es ab ("unable to change to root gid: Operation not
permitted"), selbst wenn sudoers korrekt konfiguriert ist.

Ein erster Verifikationsversuch per `runuser -u archivmail -- sudo ...`
hatte faelschlich Erfolg gemeldet, weil runuser den restriktiven
Bounding-Set der Unit nicht traegt - nur ein Test im echten
systemd-Unit-Kontext (systemd-run oder echter API-Call) ist aussagekraeftig.

Fix: CapabilityBoundingSet in update.sh und install.sh um CAP_SETUID
CAP_SETGID erweitert. AmbientCapabilities bleibt unveraendert (der Go-Daemon
selbst soll diese Rechte nie dauerhaft halten, nur der sudo-Kindprozess
braucht sie im Bounding-Set verfuegbar).
This commit is contained in:
sysops
2026-07-05 20:10:30 +02:00
parent 7300a696ca
commit af897948be
3 changed files with 119 additions and 5 deletions
+8 -1
View File
@@ -755,7 +755,14 @@ User=${AM_USER}
Group=${AM_USER}
# CAP_NET_ADMIN: required for the admin "enable firewall" action (nft -f /etc/nftables.conf)
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
# PROJ-68: CAP_SETUID/CAP_SETGID are NOT ambient (the Go daemon itself must
# never hold them) but must be in the bounding set so the setuid-root sudo
# child process (spawned by the admin "Dienste"-Tab for systemctl actions)
# can actually change to uid/gid 0. Without this, sudo aborts with
# "unable to change to root gid: Operation not permitted" even though the
# sudoers NOPASSWD rule is correct — verified 2026-07-05, see
# features/PROJ-68-sudo-provisionierung-dienststeuerung.md.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_SETUID CAP_SETGID
ExecStart=${INSTALL_DIR}/archivmail --config ${CONFIG_DIR}/config.yml
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure