devutils/ATFQ/book ATFQ git

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 docker group 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

alice@laptopexample
$ 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

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.

Commands
id podman docker
Paths
/etc/subuid /etc/subgid /run/docker.sock
See also
7.2 Namespaces: a private view of the system
15.4 ACLs and capabilities
15.3 sudo and groups