Podman rootless containers binding to privileged ports when sysctl changes are restricted
0 reputation · 10 Jan 2025, 21:56 UTC
0 reputation · 10 Jan 2025, 21:56 UTC
Goal: Allow rootless Podman containers to bind to privileged ports such as 80 without modifying the host’s net.ipv4.ip_unprivileged_port_start sysctl, so that the same configuration that works locally can be used in production.
Constraint: In many production hosts the sysctl is locked down by security policies (SELinux, AppArmor, or privileged‑container restrictions), preventing the administrator from lowering ip_unprivileged_port_start and causing bind‑permission failures.
Uncertainty: It is not documented whether Podman can automatically request or use alternative privileges (e.g., CAP_NET_BIND_SERVICE) or a per‑user‑namespace sysctl override to achieve the same result, leaving administrators to decide between relaxing host‑level settings or seeking another approach.
Can rootless Podman containers be granted CAP_NET_BIND_SERVICE to bind to ports <1024 without changing ip_unprivileged_port_start? Is there a safe per‑user‑namespace method to lower the unprivileged port start? What is the recommended practice for production environments that prohibit host‑level sysctl changes?
30775 reputation · 11 Jan 2025, 05:49 UTC
No — you cannot grant a rootless Podman container CAP_NET_BIND_SERVICE to bypass the privileged-port restriction, and there is no per-user-namespace override for net.ipv4.ip_unprivileged_port_start. The recommended production pattern is socket activation: let a privileged host process (systemd) bind port 80 and pass the open socket into the container.
Rootless Podman runs inside an unprivileged user namespace. Capabilities inside that namespace are only valid against resources the namespace owns — they confer no privilege over the host network stack. When the container's runtime tries to bind port 80, the host kernel checks the host's ip_unprivileged_port_start against the real (unmapped) UID, and the bind fails regardless of what capabilities the container claims. On locked-down hosts, SELinux or AppArmor may block the attempt even earlier. So --cap-add=CAP_NET_BIND_SERVICE is a dead end for this goal — treat that as expected behavior, not a misconfiguration.
Likewise, ip_unprivileged_port_start is a host-global sysctl; it is not namespaced per user, so an unprivileged user cannot lower it for their own containers.
Podman supports socket-activated services. systemd (running as root or via a system unit) binds the privileged port and hands the file descriptor to the container, which then only needs to accept connections on an already-open socket — no capability, no sysctl change.
# /etc/systemd/system/myapp.socket
[Socket]
ListenStream=80
[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp.service
[Service]
ExecStart=/usr/bin/podman run --rm --network=none myimage
# container reads the passed FD (LISTEN_FDS protocol)Your container image must accept the inherited socket (many frameworks support systemd socket activation, or you can use a small wrapper). Alternatively, run a minimal host-side reverse proxy (nginx, HAProxy, or socat) as a privileged unit that forwards port 80 to the rootless container's high port — this keeps the app image unchanged.
podman run --rm --cap-add=CAP_NET_BIND_SERVICE -p 80:80 alpine nc -l -p 80 should fail with a bind permission error on a host where ip_unprivileged_port_start is above 80.ss -ltnp on the host: systemd (or the proxy) owns port 80; podman ps shows no published privileged port.Where host sysctls are frozen by policy, standardize on either systemd socket activation or a hardened host-side proxy. The proxy option is usually easier to operate (TLS termination, health checks, least-privilege service unit) and keeps the rootless container identical between local and production environments — only the host unit file differs. One caveat for review: exact socket-passing mechanics vary with Podman version, so verify against your deployed release's documentation before rollout.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.