Docker Tutorial · Production Practices · Lesson 22 of 26

Non-Root Users and Read-Only Containers

Reduce what a compromised container can do: run as a non-root user, use a read-only filesystem and drop capabilities.

Create a free account to save this page, take notes and track your progress. Sign in

Defaults to change

By default the process in many images runs as root inside the container. Container root is restricted, but a container escape or a mounted host path makes it far more dangerous. Harden containers:

  • USER 10001 in the Dockerfile (create the user in the image), or --user at run time.
  • --read-only root filesystem, with --tmpfs /tmp for scratch space.
  • --cap-drop ALL, adding back only what's needed (for example NET_BIND_SERVICE).
  • --security-opt no-new-privileges so setuid binaries can't escalate.
  • Never mount the Docker socket (/var/run/docker.sock) into application containers: it is root on the host.
A non-root, read-only, capability-free container
trap 'docker image rm -f rc-secure:1 > /dev/null 2>&1' EXIT
cat > Dockerfile <<'EOF'
FROM alpine:3.24
RUN adduser -D -u 10001 app
USER 10001
CMD ["sh", "-c", "id; touch /should-fail 2>/dev/null || echo 'cannot write to /'; echo ok > /tmp/scratch && echo 'can write to /tmp'"]
EOF
docker build -q -t rc-secure:1 . > /dev/null
docker run --rm --read-only --tmpfs /tmp --cap-drop ALL --security-opt no-new-privileges rc-secure:1
echo "capabilities of the process: $(docker run --rm --cap-drop ALL rc-secure:1 sh -c 'grep CapEff /proc/self/status' | tr -s '\t' ' ')"

Output

uid=10001(app) gid=10001(app) groups=10001(app)
cannot write to /
can write to /tmp
capabilities of the process: CapEff: 0000000000000000

Run this on your computer — see “Get Started” for setup.

Test yourself

Why is mounting /var/run/docker.sock into an app container dangerous?

  1. It slows Docker down
  2. Access to the Docker API is effectively root access to the host
  3. It breaks networking
  4. It's only a logging socket
Show answer

Answer: Access to the Docker API is effectively root access to the host

Anyone with the socket can start a privileged container that mounts the host filesystem.

Was this page helpful?