Rootless Podman vs Rootful with User Namespaces
Rootless Podman is often presented as the secure way to run containers, full stop. We run rootful Podman with --userns=auto instead. Not because rootless is bad — because for our threat model, the isolation that matters comes from the user namespace, and running rootful gives us simpler networking, faster storage, and fewer moving parts.
This is the companion to our userns=auto deep-dive; that post explains the mechanism, this one explains the choice.
What rootless Podman gives you
Running Podman as an unprivileged user means everything — image pulls, container setup, the conmon monitor processes — runs without host-root privileges. If an attacker escapes a container, they land with only that user's privileges. There is no root daemon to target at all. On a shared developer machine or a multi-user host, that is a meaningful layer of protection, and we recommend it there without hesitation.
The isolation that matters: the user namespace
But the boundary that decides what happens after a container breakout is the UID mapping, not which account invoked Podman. With --userns=auto, each container gets its own subordinate UID/GID range, and root inside the container maps to an unprivileged UID on the host. An escaped process is still just that UID as far as the kernel is concerned — the same outcome rootless gives you for the workload itself. The kernel enforces the mapping identically in both modes.
What we run instead
On every Bundar-managed server, Podman runs under the configured SSH account and every application container gets --userns=auto with a per-container range carved out of /etc/subuid and /etc/subgid, which Bundar provisions during server setup. Each workload is isolated from the host and from the other workloads on the same machine by the kernel's UID mapping — the same primitive rootless relies on.
The honest tradeoff, both directions
What rootless does better: the management plane. With rootless, Podman itself never holds root, so a vulnerability in the runtime or its helpers is contained to the invoking user. In our setup, that plane still runs as root, and we won't pretend otherwise.
What rootful with --userns=auto does better, and why it matters on a server whose only job is running your apps:
- Privileged ports directly. Containers can bind ports below 1024 with no userland networking shim in the path.
- Native overlayfs. No
fuse-overlayfsperformance penalty on container storage. - Real bridge networking. No
pasta/slirp4netnstranslation layer between containers and the host network. - Plain systemd units. System units, no per-user
lingerconfiguration to keep alive.
Fewer layers between your application and the kernel means fewer things to debug at 2 AM.
Why it's the right call for a deployment platform
Our servers are single-purpose: one deploy account, running your workloads, nothing else. The multi-user protection that makes rootless shine on shared machines doesn't apply here — there is no second user to protect workloads from. What does apply is operational simplicity, and rootful with automatic user namespaces gives us the workload isolation we need without the networking and storage compromises.
Daniel J Walsh has described rootless Podman with --userns=auto as "probably the most secure" combination. We run the second half of that pairing — the half that isolates workloads from each other and from the host. For a fleet of single-tenant app servers, that half carries the weight.
What would make us reconsider
If the threat model changed — say, mutually untrusting tenants sharing one host — the management-plane argument for rootless would win outright, and we'd switch. Security choices should follow the threat model, not the slogan. Ours says: contain the workloads with user namespaces, keep the platform simple, and be explicit about where root still lives.