✦ For everyone, free.

Practical knowledge for real and everyday life

Home

14.1.3.4 Host User Permissions

A focused guide to Host User Permissions, connecting core concepts with practical Docker and container operations.

Host user permissions in a Docker production environment describe how access to the Docker daemon is controlled on the host operating system, why that access is functionally equivalent to root, and the practices used to grant container management capability to operators and automation without granting unrestricted control over the entire host.

Why Docker access is equivalent to root

The Docker daemon runs as root and listens on a Unix socket, typically /var/run/docker.sock. Any user or process that can write to that socket can launch containers with arbitrary bind mounts, including mounting the host's root filesystem into a container and then operating on it as root from inside that container. This means membership in the docker group, or any other mechanism that grants socket access, is equivalent to unrestricted root access on the host, even though no sudo password is ever requested.

docker run -v /:/host -it alpine chroot /host

A container started this way has full read and write access to the entire host filesystem, demonstrating why docker group membership cannot be treated as a lesser privilege than root.

The docker group

By default, the Docker installation creates a docker group, and adding a user to it allows that user to run Docker commands without sudo:

usermod -aG docker deploy
groups deploy

The user must start a new login session for the group membership to take effect, since group membership is read when a session begins:

su - deploy

In production, only accounts that genuinely need full container management capability should be added to this group, and that list should be reviewed the same way root access is reviewed, since functionally that is what is being granted.

Rootless Docker

Rootless mode runs the Docker daemon and all containers entirely within an unprivileged user's namespace, removing the equivalence between daemon access and host root:

dockerd-rootless-setuptool.sh install
systemctl --user start docker
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock

With rootless mode, a user who can run docker commands is still confined to their own user namespace and cannot, for example, bind-mount and chroot into the real host filesystem as root, because no real root privilege is held by the daemon process at all. This comes at the cost of reduced functionality in some networking and storage driver configurations compared to the traditional rootful daemon.

Restricting access without rootless mode

When rootless mode is not in use, access to the Docker socket should still be scoped as tightly as possible. Socket permissions can be checked directly:

ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 Jan  1 00:00 /var/run/docker.sock

The group ownership shown here is what actually gates access; any account outside the docker group, and outside root, has no path to the daemon through the socket.

Permissions inside the container

Separately from host access, the user a process runs as inside a container determines what that process can do to files it touches, including bind-mounted host directories. Running as root inside the container is the default unless explicitly changed, which means a containerized process writing into a bind-mounted host directory creates files owned by root on the host as well:

FROM node:20
RUN useradd --create-home appuser
USER appuser
WORKDIR /home/appuser/app
COPY --chown=appuser:appuser . .
CMD ["node", "server.js"]
docker run -v /srv/app/data:/home/appuser/app/data my-image

Switching to a non-root USER inside the image is the primary control for limiting what a compromised or misbehaving process inside the container can do to the host filesystem through a bind mount, independent of whether the host account running docker itself has broad privileges.

User namespace remapping

Docker also supports remapping container UIDs to an unprivileged range of host UIDs, so that a process that is root inside the container maps to a non-root, low-privilege user on the host:

{
  "userns-remap": "default"
}
systemctl restart docker

After enabling this setting, a process running as UID 0 inside a container is actually running as a high, unprivileged UID on the host, so even root-equivalent behavior inside the container does not translate into root-equivalent behavior against the host filesystem outside of what was explicitly bind-mounted and made writable to that mapped UID.

Service accounts for automation

CI/CD pipelines and deployment automation that need to run docker build or docker push should use a dedicated service account rather than a shared human operator account, so that access can be revoked, rotated, and audited independently of any individual's personal credentials:

useradd --system --no-create-home deploy-bot
usermod -aG docker deploy-bot

Audit logging of what that account does is typically handled at the orchestration layer (the CI system's own job logs) rather than by the Docker daemon itself, since the daemon's own logs do not attribute actions to the originating user once a command reaches the socket.

Common mistakes

  • Treating docker group membership as a convenience setting rather than recognizing it as equivalent to granting root access to the host.
  • Running every containerized process as the image's default root user, even when bind-mounting writable host directories, which silently grants root-owned files on the host.
  • Leaving broad docker group membership in place for accounts that no longer need it, effectively leaving a standing root-equivalent grant unreviewed.
  • Exposing the Docker socket into a container (-v /var/run/docker.sock:/var/run/docker.sock) without recognizing that doing so hands that container the same root-equivalent access the host user has.
  • Assuming user namespace remapping is enabled by default, when in most standard installations it is not, and root inside a container maps directly to root's privilege against anything it can reach.

Host user permission management for Docker production systems is ultimately an exercise in treating daemon access as a root-equivalent grant, scoping that grant to the smallest set of accounts that require it, and using rootless mode, non-root container users, or user namespace remapping to reduce the blast radius when that grant is unavoidable for broader automation needs.