Skill v1.0.1
currentAutomated scan100/100+7 new
name: hardening-docker-daemon-configuration description: Harden the Docker daemon by configuring daemon.json with user namespace remapping, TLS authentication, rootless mode, and CIS benchmark controls. domain: cybersecurity subdomain: container-security tags:
- docker
- daemon-hardening
- container-security
- cis-benchmark
- rootless
- userns-remap
version: '1.0' author: mahipal license: Apache-2.0 nist_csf:
- PR.PS-01
- PR.IR-01
- ID.AM-08
- DE.CM-01
mitre_attack:
- T1610
- T1611
- T1609
- T1525
- T1553
Hardening Docker Daemon Configuration
Overview
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
Prerequisites
- Docker Engine 24.0+ installed
- Root or sudo access to the Docker host
- OpenSSL for TLS certificate generation
- Understanding of Linux namespaces and cgroups
Core Hardened daemon.json
{"icc": false,"userns-remap": "default","no-new-privileges": true,"log-driver": "json-file","log-opts": {"max-size": "10m","max-file": "5"},"storage-driver": "overlay2","live-restore": true,"userland-proxy": false,"default-ulimits": {"nofile": {"Name": "nofile","Hard": 65536,"Soft": 32768},"nproc": {"Name": "nproc","Hard": 4096,"Soft": 2048}},"seccomp-profile": "/etc/docker/seccomp/default.json","default-address-pools": [{"base": "172.17.0.0/16","size": 24}],"iptables": true,"ip-forward": true,"ip-masq": true,"experimental": false,"metrics-addr": "127.0.0.1:9323","max-concurrent-downloads": 3,"max-concurrent-uploads": 5,"default-runtime": "runc","runtimes": {"runsc": {"path": "/usr/local/bin/runsc","runtimeArgs": ["--platform=ptrace"]}}}
Setting-by-Setting Explanation
Disable Inter-Container Communication (ICC)
{"icc": false}
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 mappingdocker 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.
TLS Configuration for Remote Docker API
Generate CA and Server Certificates
# Create CAopenssl genrsa -aes256 -out ca-key.pem 4096openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem \-subj "/CN=Docker CA"# Create server key and CSRopenssl genrsa -out server-key.pem 4096openssl req -subj "/CN=docker-host" -sha256 -new -key server-key.pem -out server.csr# Create extfile with SANsecho "subjectAltName = DNS:docker-host,IP:10.0.0.5,IP:127.0.0.1" > extfile.cnfecho "extendedKeyUsage = serverAuth" >> extfile.cnf# Sign server certificateopenssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \-CAcreateserial -out server-cert.pem -extfile extfile.cnf# Create client key and certificateopenssl genrsa -out key.pem 4096openssl req -subj "/CN=client" -new -key key.pem -out client.csrecho "extendedKeyUsage = clientAuth" > extfile-client.cnfopenssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \-CAcreateserial -out cert.pem -extfile extfile-client.cnf# Set permissionschmod 0400 ca-key.pem key.pem server-key.pemchmod 0444 ca.pem server-cert.pem cert.pem# Move to Docker TLS directorysudo mkdir -p /etc/docker/tlssudo cp ca.pem server-cert.pem server-key.pem /etc/docker/tls/
Configure daemon.json for TLS
{"tls": true,"tlsverify": true,"tlscacert": "/etc/docker/tls/ca.pem","tlscert": "/etc/docker/tls/server-cert.pem","tlskey": "/etc/docker/tls/server-key.pem","hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"]}
Client Connection
docker --tlsverify \--tlscacert=ca.pem \--tlscert=cert.pem \--tlskey=key.pem \-H=tcp://docker-host:2376 version
Docker Socket Protection
# Restrict socket ownershipsudo chown root:docker /var/run/docker.socksudo chmod 660 /var/run/docker.sock# Audit Docker socket accesssudo auditctl -w /var/run/docker.sock -k docker-socket# Never mount Docker socket into containers# BAD: docker run -v /var/run/docker.sock:/var/run/docker.sock ...
Rootless Docker
# Install rootless Dockercurl -fsSL https://get.docker.com/rootless | sh# Configure environmentexport PATH=$HOME/bin:$PATHexport DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock# Start rootless daemonsystemctl --user start dockersystemctl --user enable docker# Verify rootless modedocker info | grep -i rootless# Rootless: true
Content Trust (Image Signing)
# Enable Docker Content Trustexport DOCKER_CONTENT_TRUST=1# Pull only signed imagesdocker pull library/alpine:3.18# Will fail if image is not signed# Sign and push imagedocker trust sign myregistry/myapp:1.0
Seccomp Profile
# View default seccomp profiledocker info --format '{{.SecurityOptions}}'# Use custom seccomp profiledocker run --security-opt seccomp=/etc/docker/seccomp/custom.json alpine# Verify seccomp is enableddocker inspect --format='{{.HostConfig.SecurityOpt}}' container_name
AppArmor Profile
# Check AppArmor statussudo aa-status# Use custom AppArmor profiledocker run --security-opt apparmor=docker-custom alpine# Load custom profilesudo apparmor_parser -r /etc/apparmor.d/docker-custom
Verification Commands
# Check daemon configurationdocker info# Verify userns-remapdocker info --format '{{.SecurityOptions}}'# Check ICC settingdocker network inspect bridge --format '{{.Options}}'# Audit with Docker Benchdocker run --rm --net host --pid host \-v /var/run/docker.sock:/var/run/docker.sock \-v /etc:/etc:ro \docker/docker-bench-security
Best Practices
- Never expose Docker daemon without TLS - Always use
--tlsverifyfor remote access - Enable user namespace remapping - Map container root to unprivileged host UID
- Disable ICC - Prevent default bridge network container-to-container communication
- Use rootless mode - Run Docker daemon as non-root where possible
- Enable content trust - Only pull signed images
- Configure log rotation - Prevent log files from filling disk
- Use seccomp profiles - Restrict syscalls available to containers
- Audit Docker socket - Monitor access to /var/run/docker.sock
- Run Docker Bench regularly - Automate CIS benchmark checks
- Keep Docker updated - Apply security patches promptly