The Docker daemon (dockerd) runs with root privileges and controls all container operations. Hardening its configuration through /etc/docker/daemon.json, TLS certificates, user namespace remapping, and network restrictions is essential to prevent privilege escalation, lateral movement, and container breakout attacks.
When to Use
When deploying or configuring hardening docker daemon configuration capabilities in your environment
When establishing security controls aligned to compliance requirements
When building or improving security architecture for this domain
When conducting security assessments that require this implementation
Common Misconfigurations & Verification
Remote API exposed without mTLS:"hosts": ["tcp://0.0.0.0:2376"] with "tlsverify" absent (or any listener on 2375) is unauthenticated root over the network. Verify: ss -tlnp | grep -E '2375|2376' and docker info should report TLS; client must use --tlsverify.
userns-remap defeated per-container: even with "userns-remap": "default", a container started with --userns=host (or --privileged, which implies it) maps back to real root. Confirm cat /etc/subuid shows dockremap: and that workloads do not pass --userns=host.
icc: false gives false comfort: it only blocks the default bridge; user-defined bridges still allow container-to-container traffic. Verify with docker network inspect bridge --format '{{.Options}}'.
Rootless claimed but daemon still root: check docker info | grep -i rootless returns Rootless: true and the socket is under $XDG_RUNTIME_DIR, not /var/run/docker.sock owned by root.
Socket permissions too broad: confirm /var/run/docker.sock is root:docker 660, not world-accessible, and is never bind-mounted into containers.
no-new-privileges / seccomp not applied:docker info --format '{{.SecurityOptions}}' should list and ; an empty/ seccomp is a finding.
seccomp
no-new-privileges
unconfined
Verify the full config: run docker/docker-bench-security and resolve section 2 (daemon) [WARN]s.
Prevents containers on the default bridge network from communicating. Each container must use explicit --link or user-defined networks with published ports.
Enable User Namespace Remapping
{"userns-remap":"default"}
Maps container root (UID 0) to a high unprivileged UID on the host. This prevents a container breakout from gaining root on the host.
# Verify userns-remap is activecat /etc/subuid
# Output: dockremap:100000:65536cat /etc/subgid
# Output: dockremap:100000:65536# Verify container UID mapping
docker run --rm alpine id# uid=0(root) gid=0(root) -- but host UID is 100000+
Disable New Privilege Escalation
{"no-new-privileges":true}
Prevents container processes from gaining additional privileges via setuid/setgid binaries or capability escalation.
Enable Live Restore
{"live-restore":true}
Keeps containers running during daemon downtime, enabling daemon upgrades without container restart.
Disable Userland Proxy
{"userland-proxy":false}
Uses iptables rules instead of docker-proxy for port forwarding, reducing attack surface and improving performance.
# Enable Docker Content Trustexport DOCKER_CONTENT_TRUST=1
# Pull only signed images
docker pull library/alpine:3.18
# Will fail if image is not signed# Sign and push image
docker trust sign myregistry/myapp:1.0
Seccomp Profile
# View default seccomp profile
docker info --format '{{.SecurityOptions}}'# Use custom seccomp profile
docker run --security-opt seccomp=/etc/docker/seccomp/custom.json alpine
# Verify seccomp is enabled
docker inspect --format='{{.HostConfig.SecurityOpt}}' container_name