Part I · How it works
7.5 Root in a container: users, capabilities and the docker group
alsorootlessrootless containersrootless podmandocker groupprivileged--privilegeddocker.socksubuidsubgidcontainer escapecontainer securityuserns-remap
TL;DR
- Without user namespaces, root in a container is root on the host, held back only by namespaces, dropped capabilities and seccomp.
- Being in the
dockergroup equals being root: anyone in it can start a container with the host's/mounted and edit any file. - Rootless containers (Podman by default, Docker in rootless mode) map container root to your own user: an escape gets only your rights.
id # in the docker group?
podman run --rm alpine id # uid=0 inside…
podman unshare cat /proc/self/uid_map # …mapped to your uid outside
On your machine
$ atfq 7.5 User alice (uid 1000, gid 1000) Groups alice, wheel, docker, 4242 Admin member of wheel: the group sudo usually trusts Umask 0022: new files 644 (rw-r--r--), new folders 755 Here no container or virtual machine detected Isolated none: the host's namespaces (pid, user, uts, ipc, cgroup, time) Can run VMs with KVM (/dev/kvm) · containers with Docker Overlays 1 overlay mount: container layers, usually
An example: Alice's laptop, one of the test machines. In your terminal, this block shows your own machine, read live.
Pitfalls
--privilegedgives every capability and every device: practically no isolation. Add only the capability you need (--cap-add).- Mounting
/var/run/docker.sockinto a container hands it control of the host. - Files a rootful container writes to a bind mount belong to root on the
host; rootless ones get IDs from your range in
/etc/subuid. - Run the application as a non-root user inside the image (
USERin the Dockerfile): defence in depth.
Deep dive 2 questions
How does rootless work?
/etc/subuid gives your user a range of IDs, such as 100000 to 165535.
A user namespace maps container ID 0 to your own ID and 1 to 65535 to
that range, so images with several users still work. Networking can't
create real interfaces without privileges, so a user-space network stack
(slirp4netns or pasta) carries the traffic.
What does root inside still have?
A reduced set of capabilities (Docker keeps about fourteen, such as CHOWN and NET_BIND_SERVICE, and drops SYS_ADMIN, SYS_MODULE and others), a seccomp filter blocking dangerous system calls, and AppArmor or SELinux labels. Each layer has been bypassed at some point; together they make escapes rare.