Docker audit fix

How to Configure Docker Rootless Mode on Linux

Rootless Docker runs dockerd and its containers inside a user namespace owned by an unprivileged account, so a container escape lands as that user instead of as host root. Install it with dockerd-rootless-setuptool.sh.

Hiren KalariyaLast reviewed: Oct 6, 2026Check rootless-mode
Low
severity
Yes
needs root or sudo
3
results it can return
6 of 8
checks in this audit

Every threshold on this page is transcribed from the docker-security-daemon-socket audit script that CtrlOps runs, and a build check fails if the two ever disagree. See all 8 Daemon & Socket checks, or how the audit runs.

Low severityNeeds sudo

What this check reads

It asks the daemon directly: docker info --format '{{.SecurityOptions}}' returns the engine's security options, and the check greps that string for rootless. Present is the PASS and absent is the WARN, with no second source and no config file involved, so the answer describes only the daemon the audit managed to connect to. A daemon that could not be reached at all produces the SKIP rather than a WARN.

When it applies

Needs a reachable daemon (root, sudo, or docker group); otherwise SKIP. It asks docker info for its security options and looks for the string rootless. It therefore describes the daemon the audit connected to: on a host running a rootful daemon plus a per-user rootless one, the result depends entirely on which socket the audit reached. WARN is the expected outcome on a conventional installation - it is an advisory nudge, not a defect, which is why the severity is LOW.

What each result means

Result thresholds this check applies
ResultWhenWhat it means
SKIPDaemon unreachableNothing was determined. No daemon answered, so the check does not know whether one runs rootless or not.
PASSRootlessThe daemon reports rootless among its security options, so dockerd and its containers run as an unprivileged user and an escape lands there rather than on host root.
WARNDaemon runs as root (standard)The daemon the audit reached is the conventional rootful one. That is expected on most hosts, and this is a prompt to decide rather than a defect.

Why it matters

Rootless mode runs both dockerd and containers inside a user namespace as an unprivileged user; an escape lands as that user, not root. It is stronger than userns-remap (where the daemon itself is still root). OWASP Docker Cheat Sheet Rule #11 "Run Docker in rootless mode"; Docker docs "Run the Docker daemon as a non-root user". Podman is the daemonless equivalent.

Why it fails, and when it is wrong

  • Advisory (LOW): the vast majority of hosts run rootful Docker. Rootless has limitations: no privileged ports below 1024 without setcap/sysctl, slower networking (slirp4netns/RootlessKit), some storage drivers and --net=host behaviours differ, AppArmor/seccomp still apply, cgroup v2 required for resource limits.
  • If the audit runs as root against a per-user rootless daemon, docker info talks to the rootful socket (or none). Set DOCKER_HOST=unix:///run/user/<uid>/docker.sock for the audit user.

How to fix it

Install the prerequisites

On Debian and Ubuntu:

sudo apt-get install -y uidmap dbus-user-session docker-ce-rootless-extras

On RHEL and its rebuilds, sudo dnf install -y shadow-utils docker-ce-rootless-extras. The user needs at least 65,536 subordinate UIDs and GIDs:

grep "^$USER:" /etc/subuid /etc/subgid

Stop the rootful daemon if you are replacing it

If the rootless daemon replaces the system-wide one rather than running beside it:

sudo systemctl disable --now docker.service docker.socket

Run the setup tool as the target user

Log in as the account that will own the daemon directly over SSH, not through sudo or su, so it has a systemd user session.

dockerd-rootless-setuptool.sh install
systemctl --user enable --now docker
sudo loginctl enable-linger "$USER"

Point the CLI at the rootless daemon

docker context use rootless
# or: export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
docker info --format '{{.SecurityOptions}}'

Run the audit as this user too, or it will keep reaching the rootful daemon, or none.

Verify the fix

docker info --format '{{.SecurityOptions}}'
# expected for rootless: [... name=rootless ...]

# Which daemon are you actually talking to?
docker context ls
echo "$DOCKER_HOST"
ps -o user=,args= -C dockerd | head

# On a rootless install, the daemon runs as your user, not root:
systemctl --user status docker

Debugging

The audit account could not talk to any daemon. Check systemctl is-active docker, then docker ps as the audit user and sudo docker ps; if only the second works, run the audit as root or give the account sudo. A rootless daemon is a special case: it listens on $XDG_RUNTIME_DIR/docker.sock, so the audit only reaches it when run as the user that owns it, with DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock set or the rootless Docker context selected. The Docker Inventory check reports the same SKIP and walks through it in more detail.

Expected and usually acceptable. Rootless mode is a significant architectural change, not a config flag. Treat this as a prompt to decide, and record the decision.

The audit connected to a different daemon, most likely the rootful one. Check docker context ls and DOCKER_HOST, and re-run the audit as the user that owns the rootless daemon.

Rootless Docker cannot bind ports below 1024 by default, does not support all storage drivers or --net=host, and has slower networking. Check those constraints against your workloads before migrating; Podman is the other route to the same goal.

Different control. Rootless means the daemon is unprivileged; a container can still run as UID 0 within its user namespace. See the Container User check.

Sources

How the script reads this

Next

Re-run the Daemon & Socket audit after applying the fix and confirm this check moves to PASS. CtrlOps runs all 8 checks over your existing SSH connection and scores the result, so the change is visible without reading another config file.

All 8 Daemon & Socket fixes
Audit your fleet

Find every one of these on every server, in one click

CtrlOps runs this audit over your existing SSH connection - no agents, no scripts to manage. $7/user/month after a 1 month free trial - no credit card required.

Windows

✓ Start instantly·✓ No credit card·✓ No sneaky autorenewals