Podman user namespaces let you run containers as a non-root user on the host, but the container’s root user is actually a different, unprivileged user on the host.
Let’s see this in action. Imagine you have a user alice on your host machine with UID 1000. She wants to run a simple nginx container.
# On the host, as user alice
podman run -d --name my-nginx -p 8080:80 docker.io/library/nginx:latest
When this container starts, alice is still alice (UID 1000) on the host. However, inside the container, the root user (UID 0) is mapped to alice’s UID on the host. This means the container’s root can’t actually do anything as root on the host.
To verify this, let’s exec into the container and check the user’s UID:
# On the host, as user alice
podman exec my-nginx id
Output:
uid=0(root) gid=0(root) groups=0(root)
Inside the container, it looks like root. Now, let’s try to write a file to the root of the container’s filesystem, which is actually mapped to a user-owned directory on the host.
# On the host, as user alice
podman exec my-nginx touch /testfile
podman exec my-nginx ls -l /testfile
Output:
-rw-r--r-- 1 root root 0 May 15 10:30 /testfile
The file appears to be owned by root inside the container. But on the host, let’s find where Podman stores this container’s filesystem and check the ownership of that file:
# On the host, as user alice
# Find the container's storage location (this path is an example, it varies)
podman inspect my-nginx --format '{{.GraphDriver.Data.MergedDir}}'
# Let's say the output is /home/alice/.local/share/containers/storage/overlay2/abcdef.../merged
# Then check ownership of the file within that directory
ls -l /home/alice/.local/share/containers/storage/overlay2/abcdef.../merged/testfile
You’ll see that testfile is owned by UID 1000 (alice) and GID 1000 (alice’s primary group) on the host. This is the core of user namespaces: the container’s root (UID 0) is mapped to a non-privileged UID on the host.
This mapping is controlled by the subuid and subgid ranges configured on your system. When Podman creates a user namespace for a rootless container, it assigns a range of UIDs and GIDs from the user’s subuid and subgid files. The first UID/GID in this range becomes UID 0 inside the container, the second becomes UID 1, and so on.
For user alice (UID 1000), her subuid and subgid might look like this in /etc/subuid and /etc/subgid:
alice:100000:65536
This means that UIDs from 100000 to 165535 (100000 + 65536 - 1) are available for mapping within alice’s user namespaces. When the nginx container runs, its internal UID 0 is mapped to host UID 100000, UID 1 to 100001, and so on, up to UID 65535 which maps to host UID 165535.
The primary benefit is security: if a process inside the container escapes and gains elevated privileges, it only has the privileges of the mapped host user (e.g., alice), not the host’s actual root user.
One subtle but critical point is how Podman handles storage and network for rootless containers. For storage, it uses a layered filesystem (like overlayfs) where the lower layers are typically owned by root (as they are shared across all users) but the top writable layer is owned by the user running Podman. When user namespaces are involved, this writable layer’s ownership is further mapped. For networking, rootless Podman uses slirp4netns by default, which acts as a userspace network stack and NATs traffic from the container to the host. This is less performant than native network stacks but is essential for rootless operation as it doesn’t require host network interface manipulation.
The next step in securing rootless containers is understanding how to manage storage drivers and network configurations beyond the defaults.