deploy: add CAP_FOWNER/CAP_FSETID so entrypoint permission-fix works

Bringing up the production Apache stack for real surfaced a latent bug
in the Phase 10 hardening: cap_drop: ALL with only NET_BIND_SERVICE/
CHOWN/SETUID/SETGID/DAC_OVERRIDE left the root startup phase unable to
chmod the /data dirs it had just chowned to the panel user (needs
CAP_FOWNER) or set their setgid bit (needs CAP_FSETID). The container
crash-looped on "chmod: Operation not permitted". Phase 10 never caught
this because its compose up hit a port conflict before full boot.

Add FOWNER and FSETID to cap_add and document what each capability is
for. Verified: container now starts clean under the hardened compose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 22:18:44 +03:00
parent e8b558eb3b
commit fe2844441b
2 changed files with 17 additions and 3 deletions
+15 -3
View File
@@ -65,9 +65,19 @@ services:
# `user: panel` or a fully read-only rootfs without breaking that startup
# self-healing. What IS applied: no privilege escalation past what the
# image already grants, and every Linux capability dropped except the
# small set Postfix/OpenDKIM genuinely need (binding <1024, chown/setuid
# during startup, and DAC overrides for cross-user file access within the
# shared group).
# small set the root startup phase and Postfix/OpenDKIM genuinely need:
# - NET_BIND_SERVICE — bind 465/587 (and 25 outbound) below 1024;
# - CHOWN — entrypoint re-owns /data (bind mount) to `panel`;
# - FOWNER — entrypoint then chmods those now panel-owned /data
# dirs/files while still root (owner-check bypass);
# - FSETID — set the setgid bit (2750) on the shared /data dirs
# when the process gid differs from the dir's group;
# - SETUID/SETGID — supervisord drops the panel to the unprivileged
# `panel` user; Postfix switches to its own users;
# - DAC_OVERRIDE — cross-user file access within the `selfpost` group.
# FOWNER/FSETID are required by build/entrypoint.sh's permission
# self-healing; without them chmod fails with EPERM and the container
# crash-loops on start.
security_opt:
- no-new-privileges:true
cap_drop:
@@ -75,6 +85,8 @@ services:
cap_add:
- NET_BIND_SERVICE
- CHOWN
- FOWNER
- FSETID
- SETUID
- SETGID
- DAC_OVERRIDE