Image and Runtime Security
Container security is layered: run with the least privilege, ship the least software, keep secrets out of images, and verify what you deploy. Most incidents come from one setting that quietly undoes the rest, such as a mounted Docker socket or `--privileged`.
Key points
- 1
Images run as root unless they set
USERor you pass--user. Without user namespaces, that is UID 0 on the host kernel too, so default to a non-root UID. - 2
Docker drops many capabilities by default. Go further with
--cap-drop ALLplus only what you need, and treatCAP_SYS_ADMINand--privilegedas nearly full host access. - 3
Access to the Docker socket, the
dockergroup or an unauthenticated TCP API all mean root on the host. Remote access should use SSH or TLS with--tlsverify. - 4
Never put secrets in
ENV,ARGor copied files: they persist in layers, history and max-mode provenance. Use BuildKit secret or SSH mounts for builds, and runtime secrets mounted under/run/secrets. - 5
Cheap runtime hardening:
--read-onlywith--tmpfsfor scratch,--security-opt no-new-privileges, the default seccomp profile, and--memoryand--pids-limitlimits. - 6
Supply chain: pin base images by digest, verify signatures (cosign), produce SBOM and provenance attestations, scan continuously, and rebuild when bases are patched.
- 7
Rootless mode runs the daemon itself as a normal user. Low ports need
CAP_NET_BIND_SERVICEon rootlesskit or a sysctl, and limits need cgroup v2 with systemd.
Common traps
Deleting a secret in a later layer does not remove it from the earlier layer that added it.
Mounting the Docker socket with
:rostill allows every API call.Published ports bypass ufw rules; bind to
127.0.0.1or filter in theDOCKER-USERchain.
Read the source
Test yourself on Image and Runtime Security
Ten questions, with the answer and explanation after each one.