Daemon & socket hardening
Protect docker.sock; lock down daemon.json.
If you do run the traditional root daemon, its Unix socket /var/run/docker.sock is the crown jewel: the Docker API is unauthenticated at the socket level, and anyone who can write to it can start a container that bind-mounts the host root filesystem and read or write anything as root. So the first rule of daemon hardening is that socket access equals root, and it must be guarded exactly that tightly — never mounted into containers casually, never exposed over the network without mutual TLS.
# why socket access = host root: mount the host root via a new container and chroot in$ docker -H unix:///var/run/docker.sock run -v /:/host -it alpine chroot /host sh# whoever can reach the socket just became root on the host filesystem.$ ls -l /var/run/docker.socksrw-rw---- 1 root docker ... # membership in "docker" is root-equivalent
Never expose the API over plain TCP
Turning on -H tcp://0.0.0.0:2375 to “manage Docker remotely” publishes an unauthenticated root API to the network — routinely scanned and cryptomined within hours. If you must expose the API, use the TLS port (2376) with mutual certificate auth so only clients holding a signed cert can connect, and firewall it to known hosts. Better, do not expose it at all; use SSH or a rootless/remote context.
{"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],"tls": true,"tlsverify": true, // require a client cert (mutual TLS)"tlscacert": "/etc/docker/ca.pem","tlscert": "/etc/docker/server-cert.pem","tlskey": "/etc/docker/server-key.pem","no-new-privileges": true, // default no-new-privileges for all containers"userns-remap": "default", // remap container root (next lesson)"icc": false, // no inter-container comms on default bridge"live-restore": true}
Daemon-wide safe defaults
daemon.json is where you set defaults that every container inherits, so a forgetful docker run is still reasonably safe: no-new-privileges: true bakes in the escalation block, userns-remap enables UID mapping, icc: false disables inter-container traffic on the default bridge, and a default seccomp profile stays applied. Combine that with CIS-Docker-benchmark checks (docker-bench-security scores the host against them) to catch drift.
$ docker run --rm --net host --pid host --cap-add audit_control \-v /etc:/etc:ro -v /var/lib:/var/lib:ro -v /var/run/docker.sock:/var/run/docker.sock:ro \docker/docker-bench-security # audits the daemon + host against CIS Docker[WARN] 2.1 - Restrict network traffic between containers (icc)[PASS] 2.11 - Ensure that authorization for Docker client commands is enabled