skip to content

A colleague enables the Docker daemon's --userns-remap option. Explain what user-namespace remapping does to the UIDs a container sees versus the UIDs the host kernel sees, and where the mapping ranges come from.

level: middleimportance: should knowfreq 44%

answer

  1. /etc/subuid + /etc/subgid ranges
  2. dockremap user, offset 165536
  3. uid_map: inside, outside, length
  4. /var/lib/docker/<uid>.<gid> — re-pull images
  5. daemon-wide mapping, --userns=host opts out

basics

~20 s

The daemon puts containers in their own user namespace. Inside, the process still sees UID 0; the kernel maps that to an unprivileged host UID from a subordinate range in /etc/subuid and /etc/subgid, typically belonging to a user named dockremap.

solid answer

~40 s

With `--userns-remap`, the daemon starts each container in a user namespace whose UID/GID range is shifted. Inside the container nothing looks different — `id` still reports 0 for root — but the kernel translates that to a high, unprivileged host UID such as 165536. The range comes from the subordinate-ID files `/etc/subuid` and `/etc/subgid`; `--userns-remap=default` makes the daemon create a `dockremap` user and allocate a 65536-wide block for it. Consequences: root in the container has full privilege *within the namespace* only, so writes to bind-mounted host paths are checked against the mapped UID, and privileged operations on non-namespaced kernel resources fail. Image and container storage moves to `/var/lib/docker/<uid>.<gid>/`, so images are pulled again after enabling it. The mapping is daemon-wide, not per-container — every container gets the same range unless started with `--userns=host`.

code

bash · 9 lines
bash
cat /etc/docker/daemon.json
# { "userns-remap": "default" }
sudo systemctl restart docker

grep dockremap /etc/subuid /etc/subgid
# /etc/subuid:dockremap:165536:65536
# /etc/subgid:dockremap:165536:65536

sudo ls -ld /var/lib/docker/165536.165536

go deeper

for a junior

Know the one-line idea: in-container root is mapped to a harmless high host UID drawn from /etc/subuid.

for a middle

Be able to point at daemon.json, the subuid/subgid ranges, uid_map, and the storage-directory change, and explain why bind mounts break.

for a senior

Add the limits: one shared mapping for all containers, no help against the daemon socket or kernel bugs, and the operational cost of re-pulling images and re-owning volumes.

for a principal

Weigh remapping against per-workload non-root UIDs and rootless daemons, and decide whether the host-isolation gain justifies the volume and feature friction across the fleet.

## The mechanism A user namespace is the kernel feature that lets a process have a different UID/GID *view* than the host. Each namespace carries a mapping table — visible in `/proc/<pid>/uid_map` — of the form "inside-ID, outside-ID, length". Docker's `--userns-remap` daemon flag turns this on for containers: a container gets a mapping like `0 165536 65536`, meaning in-container UID 0 is host UID 165536, in-container UID 1 is 165537, and so on for 65536 IDs. Inside the container nothing appears different. `id` reports uid=0, `ls -l /` shows root-owned files, package managers work. The translation is invisible to the workload, which is the point: unmodified images that insist on being root keep working while the host sees an unprivileged account. ## Where the range comes from Subordinate IDs are a long-standing Linux concept: `/etc/subuid` and `/etc/subgid` record, per user, which ID ranges that user may hand out inside namespaces they create. A line reads `dockremap:165536:65536`. `--userns-remap=default` tells the daemon to create the user `dockremap` and its subordinate entries automatically. You can instead pass a username, a UID, or `uid:gid` to reuse an existing account and range. Configure it persistently in `/etc/docker/daemon.json` with `"userns-remap": "default"` and restart the daemon. ## What changes operationally - **Storage is namespaced.** Because layers must be owned by the remapped IDs, the daemon uses `/var/lib/docker/<uid>.<gid>/` as its root. Existing images and containers in the un-remapped root become invisible; you re-pull. Turning the option off later switches back to the original directory. - **Bind mounts need matching ownership.** A host directory owned by `root` is not writable by a container root that maps to 165536. This is the friction people hit first. - **Capabilities become namespace-scoped.** In-container root holds a full capability set, but only over resources the namespace owns. Operations on non-namespaced kernel state — loading modules, most raw device access, changing the host clock — fail. - **It is daemon-wide and shared.** All containers get the same mapping, so container A's root and container B's root are the *same* host UID. Remapping isolates containers from the host, not from each other. Per-container `--userns=host` opts a specific container out. ## How it differs from rootless mode Both use user namespaces, but at different layers. With `--userns-remap` the daemon itself still runs as real root and only containers are shifted. Rootless mode runs the whole daemon as an ordinary user. Remapping therefore does nothing about the daemon's own attack surface; it narrows what a container process can do to the host. ## Verifying it Check `/proc/<container-pid>/uid_map` from the host, or run `ls -n` on a file the container created in a volume: an in-container `chown root:root` shows up on the host as `165536 165536`. `docker info` also reports the userns security option.

  • After enabling --userns-remap, all previously pulled images seem to be gone. Why?
    The daemon switches its data root to /var/lib/docker/<uid>.<gid>/ so that layer files are owned by the remapped IDs. The old images still exist under the original data root but are not used while remapping is on. You re-pull once; disabling the option restores the previous directory and its images.
  • Does remapping isolate containers from each other?
    Not by default. The daemon uses one shared mapping, so in-container UID 0 in every container resolves to the same host UID. Two containers sharing a volume can therefore read and write each other's files just as before; remapping raises the wall between container and host, not between containers.

It is like a hotel numbering scheme: the guest reads Room 0 on their key, but the building's master list calls it 165536 — same door, different registry.

saying these in an interview costs you the question

  • Confusing --userns-remap with rootless mode (the daemon still runs as root here)
  • Expecting the container's own view of UIDs to change
  • Thinking each container gets a distinct UID range by default
  • Forgetting that bind-mount ownership must be shifted into the mapped range
  • Believing remapping stops kernel exploits or protects a mounted daemon socket

context