SECURITY / Docker · 25 min

Reduce container privileges

Run a small container with a non-root user, fewer privileges, and limited writes. Inspect the result rather than trusting the flags.

Before you start

Environment: Docker Engine with Linux containers, or Docker Desktop in Linux-container mode. Bash commands; the Alpine image must be available or pulled. No application or cluster setup required.

Use a disposable container with a unique name. Do not mount the host root, home directory, or Docker socket. The example image tag is convenient for practice; production images need a reviewed digest and update policy.

Commands run in your own terminal. This website cannot inspect or secure your environment.

Inspect · daemon context

1. Know who controls the daemon

A non-root process inside a container does not make a rootful Docker daemon unprivileged.

Bash · review before running
docker context show
docker info --format "{{json .SecurityOptions}}"

What to check

Record the active daemon and its security options. Rootless mode should be explicitly reported if configured. Docker Desktop uses a VM; that is a different setup from native rootless Docker.

Try it deliberately

Review who can reach the socket or Docker API. Rootful socket access can grant host-level control. Evaluate rootless mode against your workload and platform requirements before changing daemon configuration.

Recovery & cleanup

No daemon change is needed for this inspection. If experimenting with rootless mode later, preserve the old context and follow the official migration guidance.

Official guidance: Docker daemon security ↗ · Docker rootless mode ↗

Practice · starts one temporary container

2. Prove the runtime restrictions

Start with the privileges the task needs, then investigate a specific failure before granting more.

Bash · review before running
docker run --rm --network none --user 65534:65534 \
  --read-only --tmpfs /tmp:rw,noexec,nosuid,size=16m \
  --cap-drop ALL --security-opt no-new-privileges=true \
  --memory 64m --cpus 0.5 --pids-limit 64 \
  alpine:3.22 sh -c 'id; grep NoNewPrivs /proc/self/status; if touch /etc/blocked; then exit 1; fi; echo ok > /tmp/probe; cat /tmp/probe'

What to check

uid=65534, NoNewPrivs: 1, a read-only filesystem error for /etc/blocked, and ok from /tmp. The container exits and --rm removes it. Pull alpine:3.22 first if it is not cached.

Try it deliberately

For a real application, document every required writable path, network connection, and capability. Keep Docker’s default seccomp profile enabled; do not fix an error by adding --privileged or seccomp=unconfined.

Recovery & cleanup

This container has no persistent volume and removes itself. If an application needs storage, mount only its state directory and keep a backup; do not make the entire filesystem writable as the first fix.

Official guidance: Docker runtime options ↗ · Docker default seccomp profile ↗

Inspect · replace the example container name

3. Review ports, images, and credentials

Container isolation does not solve accidental publication or credentials embedded in an image.

Bash · review before running
docker ps --format "table {{.Names}}\t{{.Ports}}"
# Replace demo-api with an existing practice container
docker inspect demo-api --format "user={{.Config.User}} readonly={{.HostConfig.ReadonlyRootfs}} privileged={{.HostConfig.Privileged}}"
docker port demo-api

What to check

The declared user, filesystem policy, privilege setting, and port mappings match your intent. A blank User means the image default applies, often root; confirm with the image documentation and runtime id.

Try it deliberately

Use 127.0.0.1:8080:8080 for a service intended only for local access; verify externally too. Review image provenance, scan findings, and rebuilds. Keep credentials out of Dockerfile ARG/ENV and image layers; use build-secret mounts and a runtime secret delivery mechanism.

Recovery & cleanup

Change published ports by recreating the practice container from its reviewed configuration. Keep persistent data outside the container and restore the prior configuration if the health check fails.

Official guidance: Docker port publishing ↗ · Docker build secrets ↗

Reviewed 31 October 2026. Adapt to your installed versions and environment; these guides cover selected controls, not a compliance certification.