Retain Caddy file capability at ingress boundary

This commit is contained in:
2026-08-03 20:02:29 +02:00
parent d107d94fec
commit 1f039dd39c
5 changed files with 12 additions and 0 deletions
@@ -185,6 +185,11 @@ The dispatch-only `Runtime Ingress Drill` workflow exposes the same bounded
check independently so ingress changes can be diagnosed before an immutable
runtime publication; it accepts only digest-pinned Caddy, HAProxy, and API
images and has no push trigger.
The official Caddy binary carries the `NET_BIND_SERVICE` file capability. The
managed-ingress container therefore drops every capability and adds back only
`NET_BIND_SERVICE`; otherwise Linux rejects the binary at `execve` before its
high-port configuration can start. `no-new-privileges`, a read-only root
filesystem, and non-privileged container ports remain enforced.
The bounded setup helper writes only generated public configuration as root so
it can initialize a new volume; the actual HAProxy process retains the image's
non-root identity and runs read-only with all capabilities dropped.
+3
View File
@@ -551,6 +551,9 @@ class DeploymentInstallerTests(unittest.TestCase):
)
self.assertIn("caddy-data:/data", ingress["volumes"])
self.assertIn("caddy-config:/config", ingress["volumes"])
self.assertEqual(["ALL"], ingress["cap_drop"])
self.assertEqual(["NET_BIND_SERVICE"], ingress["cap_add"])
self.assertEqual(["no-new-privileges:true"], ingress["security_opt"])
self.assertIn("reverse_proxy load-balancer:8080", render_caddy_config(spec))
self.assertNotIn("operator@example.test", json.dumps(compose))
+1
View File
@@ -64,6 +64,7 @@ class ManagedIngressDrillTests(unittest.TestCase):
self.assertNotIn('"127.0.0.1::8080"', source)
self.assertIn("requested_http_port", source)
self.assertIn("requested_https_port", source)
self.assertIn('"--cap-add",\n "NET_BIND_SERVICE"', source)
def test_published_port_reads_the_docker_mapping(self) -> None:
completed = subprocess.CompletedProcess(
+2
View File
@@ -388,6 +388,8 @@ def main() -> int:
"no-new-privileges",
"--cap-drop",
"ALL",
"--cap-add",
"NET_BIND_SERVICE",
"--publish",
f"127.0.0.1:{requested_http_port}:8080/tcp",
"--publish",
@@ -627,6 +627,7 @@ def render_compose(spec: InstallationSpec) -> dict[str, object]:
"tmpfs": ["/tmp:rw,noexec,nosuid,size=64m"],
"security_opt": ["no-new-privileges:true"],
"cap_drop": ["ALL"],
"cap_add": ["NET_BIND_SERVICE"],
"volumes": [
f"./{CADDY_CONFIG_FILENAME}:/etc/caddy/Caddyfile:ro",
"caddy-data:/data",