Hardening a running container
Drop root, freeze the filesystem and remove capabilities so one bug is not a host takeover.
Open this lesson in the learning hubKey points
- Root in the container is root on the host kernel. Add a
USERwith a fixed uid and never run production as root. --read-onlyfreezes the image filesystem. Hand the app a writable--tmpfs /tmpand nothing else.--cap-drop ALLremoves the capabilities Docker grants by default. A JVM serving port 8080 needs none of them.--security-opt no-new-privilegesblocks setuid escalation, so a stray setuid binary cannot hand root back.- Never mount
/var/run/docker.sockinto an application container. It is a root shell on the host with extra steps. - Never reach for
--privilegedto silence a permission error. Find the single capability you actually need.
Example
# Dockerfile
RUN useradd --system --uid 10001 appuser
USER 10001
# run it with the fence up
docker run -d --name api \
--user 10001:10001 \
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m \
--cap-drop ALL \
--security-opt no-new-privileges \
--pids-limit 200 --memory=1g --cpus=2 \
-p 127.0.0.1:8080:8080 myapp:1.0
# audit what a running container was actually given
docker inspect --format "{{.Config.User}} {{.HostConfig.Privileged}} {{.HostConfig.ReadonlyRootfs}}" api
Non-root, read-only, no capabilities. Four flags, most of the blast radius gone.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Docker course, and every lesson in it is listed on the Docker contents page.