CIS Docker Benchmark
Secure configuration guidelines for Docker Engine and container workloads
v1.7.0 January 2025Overview
▶This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for Docker Engine. It covers host configuration, daemon security, container images, runtime security, and operational best practices.
| Section | Area | Recommendations | Focus |
|---|---|---|---|
| 1 | Host Configuration | ~35 | Filesystem, partitioning, audit daemon |
| 2 | Docker Daemon Configuration | ~50 | Network, security features, runtime options |
| 3 | Container Images | ~25 | Image provenance, Dockerfile hardening |
| 4 | Container Runtime | ~45 | Security config, resource limits, capabilities |
| 5 | Docker Security Operations | ~25 | Secrets management, Swarm security |
Profile Definitions
▶| Profile | Description | Intended Use |
|---|---|---|
| L1 | Level 1 — Base Security | Essential security settings for all Docker deployments. Minimal operational impact. |
| L2 | Level 2 — Defense in Depth | Advanced hardening for high-security environments. May require changes to workflows. |
1 — Host Configuration
▶Recommendations for securing the Docker host operating system, filesystem layout, and audit configuration.
1.1 Filesystem & Partitioning
▶Docker stores all images, containers, and local volumes under /var/lib/docker. A dedicated partition prevents container storage from filling the root filesystem.
The absence of a Separate Partition for /var/lib/docker leaves the Docker container platform without an important security control. Verifying its presence ensures the system meets the minimum security baseline required by the CIS benchmark.
mountpoint /var/lib/docker # Should return: /var/lib/docker is a mountpoint grep '/var/lib/docker' /etc/fstab
Create a dedicated partition or logical volume for /var/lib/docker and add it to /etc/fstab.
Members of the docker group have root-equivalent privileges on the host via Docker socket access. Limit group membership to trusted users only.
Failure to only Trusted Users Are in the Docker Group may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
getent group docker # Review all listed users
# Remove untrusted users: gpasswd -d <user> docker
The Docker socket /var/run/docker.sock provides root-level access to the host via Docker API. Restrict its permissions.
Incorrect permissions on Docker Socket could allow unauthorized reading, writing, or execution of critical files. Proper file permissions are a foundational control that prevents privilege escalation and data tampering.
stat -c '%U:%G %a' /var/run/docker.sock # Should be root:docker 660
chown root:docker /var/run/docker.sock chmod 660 /var/run/docker.sock
1.2 Audit & Logging
▶Configure Linux audit rules for Docker files and directories. Audit events provide traceability for security investigations.
Failure to auditing Is Configured for Docker Files may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
auditctl -l | grep docker # Should include rules for: # /usr/bin/dockerd, /var/lib/docker, /etc/docker, # /var/run/docker.sock, /etc/default/docker
# Add to /etc/audit/rules.d/docker.rules: -w /usr/bin/dockerd -k docker -w /var/lib/docker -k docker -w /etc/docker -k docker -w /var/run/docker.sock -k docker -w /usr/lib/systemd/system/docker.service -k docker -w /usr/lib/systemd/system/docker.socket -k docker -w /etc/default/docker -k docker -w /etc/docker/daemon.json -k docker # Restart auditd: systemctl restart auditd
Configure a logging driver for the Docker daemon. The default json-file driver stores logs locally. For production, use a centralized logging driver.
Misconfiguration of Docker Daemon Logging can lead to security gaps that may be exploited by attackers. A properly configured Docker container platform reduces exposure to both known vulnerabilities and configuration drift.
docker info --format '{{ .LoggingDriver }}'
# Should return the configured driver
cat /etc/docker/daemon.json | jq '.["log-driver"]'
# /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
2 — Docker Daemon Configuration
▶Recommendations for securing the Docker daemon including network configuration, security features, and runtime options.
2.1 Network Configuration
▶By default, all containers on the same Docker bridge network can communicate. Disable inter-container communication and use explicit links or networks.
Failure to network Traffic Is Restricted Between Containers may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker network inspect bridge --format '{{ .Options }}'
# Check com.docker.network.bridge.enable_icc is false
# Or:
ps -ef | grep dockerd | grep -- '--icc'
# /etc/docker/daemon.json:
{
"icc": false
}
Do not bind the Docker daemon to a TCP socket. The Docker daemon should only listen on the local Unix socket unless remote access is explicitly required with TLS.
Failure to docker Daemon Does Not Listen on TCP may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
ps -ef | grep dockerd | grep -- '-H' # Should not show tcp:// bindings cat /etc/docker/daemon.json | jq '.hosts'
Remove any -H tcp:// arguments. If remote access is required, use TLS mutual authentication:
{
"hosts": ["unix:///var/run/docker.sock"],
"tls": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"tlsverify": true
}
Docker modifies iptables rules to provide network isolation. Review changes and consider setting --iptables=false when managing firewall rules externally.
Failure to iptables Rules Are Not Altered by Docker may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
iptables -L -n | grep DOCKER # Review Docker-managed chains
If using external firewall management, set "iptables": false in daemon.json and manage rules manually.
2.2 Security Features
▶Enable user namespace remapping so that root inside the container maps to an unprivileged user on the host, reducing the impact of container breakout.
Without User Namespace Support enabled, the Docker container platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.
docker info --format '{{ .SecurityOptions }}'
# Should include userns
cat /etc/docker/daemon.json | jq '.["userns-remap"]'
# /etc/docker/daemon.json:
{
"userns-remap": "default"
}
# Verify subordinate UID/GID:
cat /etc/subuid
cat /etc/subgid
Enable Docker Content Trust (DCT) to verify image publisher identity and image integrity using digital signatures.
Without Content Trust enabled, the Docker container platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.
echo $DOCKER_CONTENT_TRUST # Should be 1
export DOCKER_CONTENT_TRUST=1 # Add to /etc/environment or shell profile for persistence
Ensure a MAC (Mandatory Access Control) system like AppArmor or SELinux is active. Docker uses these to confine container processes.
Without AppArmor or SELinux enabled, the Docker container platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.
# AppArmor:
docker info --format '{{ .SecurityOptions }}'
# Should include apparmor
# SELinux:
getenforce
# Should return Enforcing
# For SELinux (RHEL/CentOS): setenforce 1 # In /etc/selinux/config: SELINUX=enforcing # For AppArmor (Ubuntu/Debian): systemctl enable apparmor systemctl start apparmor
Apply seccomp profiles to containers to restrict the system calls available to the container process. Docker applies a default seccomp profile that blocks ~44 syscalls.
Failure to seccomp Profile Is Applied may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker inspect --format '{{ .HostConfig.SecurityOpt }}' <container_id>
# Should include seccomp profile or show default is active
docker info --format '{{ .SecurityOptions }}'
# Should include seccomp
Do not run containers with --security-opt seccomp=unconfined. Use the default profile or create custom profiles:
docker run --security-opt seccomp=/path/to/custom-profile.json ...
2.3 Runtime Options
▶Enable live restore so containers continue running when the Docker daemon is restarted. This reduces downtime during daemon upgrades.
Without Live Restore enabled, the Docker container platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.
docker info --format '{{ .LiveRestoreEnabled }}'
# Should return true
# /etc/docker/daemon.json:
{
"live-restore": true
}
Set default ulimits for all containers at the daemon level. This prevents resource exhaustion from individual containers.
Misconfiguration of Default ulimits can lead to security gaps that may be exploited by attackers. A properly configured Docker container platform reduces exposure to both known vulnerabilities and configuration drift.
docker info --format '{{ .DefaultUlimits }}'
# /etc/docker/daemon.json:
{
"default-ulimits": {
"nofile": { "Name": "nofile", "Hard": 65536, "Soft": 65536 },
"nproc": { "Name": "nproc", "Hard": 4096, "Soft": 4096 }
}
}
3 — Container Images
▶Recommendations for securing Docker container images, including provenance verification and Dockerfile hardening.
3.1 Image Provenance
▶Scan all container images for known vulnerabilities before use. Integrate scanning into CI/CD pipelines.
Failure to images Are Scanned for Vulnerabilities may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Using Trivy: trivy image <image_name> # Using Docker Scout: docker scout cves <image_name> # Using Grype: grype <image_name>
Integrate image scanning into CI/CD. Block deployments with critical or high CVEs. Rebuild images with updated base images.
Use official or verified Docker images as base images. Untrusted base images may contain backdoors or unpatched vulnerabilities.
Failure to only Trusted Base Images Are Used may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker images --format '{{ .Repository }}:{{ .Tag }}'
# Review base images used in Dockerfiles
grep -r '^FROM' */Dockerfile
Use Docker Official Images, Verified Publisher images, or images from your organization's private registry. Pin images to specific digests.
3.2 Image Hardening
▶Containers should run as a non-root user. Include a USER directive in Dockerfiles to ensure processes don't run as root.
Failure to a Non-Root USER Is Specified in Dockerfile may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check running containers:
docker inspect --format '{{ .Config.User }}' <container_id>
# Should not be empty or root/0
# Check Dockerfile:
grep '^USER' Dockerfile
FROM ubuntu:22.04 RUN groupadd -r appuser && useradd -r -g appuser appuser # ... install dependencies ... USER appuser CMD ["app"]
Include a HEALTHCHECK instruction in Dockerfiles. Health checks enable Docker to detect and restart unhealthy containers.
Failure to hEALTHCHECK Is Defined may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker inspect --format '{{ .Config.Healthcheck }}' <container_id>
# Should not be <nil>
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1
Use COPY instead of ADD in Dockerfiles. ADD has extra features (tar extraction, URL fetching) that can introduce unexpected behavior and security risks.
Failure to cOPY Is Used Instead of ADD may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
grep '^ADD' Dockerfile # Should only appear for legitimate tar extraction needs
Replace ADD <src> <dest> with COPY <src> <dest> unless tar auto-extraction is explicitly needed.
Do not embed secrets, passwords, keys, or tokens in Docker images. Secrets in images persist in all layers and can be extracted.
Failure to no Secrets Are Stored in Images may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check for common secret patterns: docker history --no-trunc <image_name> | grep -iE 'password|secret|key|token' # Use tools like TruffleHog or Dockle: dockle <image_name>
Use Docker BuildKit secrets, environment variables at runtime, or a secrets manager. Use multi-stage builds to prevent secrets from leaking to final images.
4 — Container Runtime
▶Recommendations for securing Docker container runtime configuration including security context, capabilities, and resource limits.
4.1 Security Configuration
▶Do not run containers in privileged mode. Privileged containers have full access to the host's devices and kernel capabilities.
If Privileged Mode remains used, it presents an unnecessary risk vector that attackers could exploit. Removing or disabling unused components is a fundamental principle of secure system hardening.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: Privileged={{ .HostConfig.Privileged }}'
# All should be false
Remove the --privileged flag. Grant only needed capabilities using --cap-add.
Run containers as a non-root user. Use --user flag or USER instruction to specify a non-root UID.
Failure to no Containers Run with Root User may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: User={{ .Config.User }}'
# Should not be empty or 0/root
docker run --user 1000:1000 <image>
Never mount the Docker socket (/var/run/docker.sock) inside containers. This gives the container full control over the Docker daemon and host.
Failure to docker Socket Is Not Mounted Inside Containers may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: {{ range .Mounts }}{{ .Source }} {{ end }}' | grep docker.sock
# Should return empty
Remove Docker socket mounts. For CI/CD, use Docker-in-Docker (DinD) with --privileged in isolated VMs, or use Kaniko/Buildah for image builds.
Mount the container's root filesystem as read-only. Use volume mounts for directories that require write access.
Failure to containers Use Read-Only Root Filesystem may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: ReadOnly={{ .HostConfig.ReadonlyRootfs }}'
# Should be true
docker run --read-only --tmpfs /tmp:rw,noexec,nosuid <image>
Drop all Linux capabilities and only add those specifically needed. Docker grants a default set of capabilities that is more permissive than necessary.
Failure to all Capabilities Are Dropped may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: CapDrop={{ .HostConfig.CapDrop }} CapAdd={{ .HostConfig.CapAdd }}'
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE <image>
4.2 Resource Limits
▶Set memory limits for all containers to prevent a single container from exhausting all host memory.
Failure to memory Limits Are Set may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: Memory={{ .HostConfig.Memory }}'
# Should not be 0 (unlimited)
docker run --memory=512m --memory-swap=1g <image>
Set CPU limits for all containers to prevent CPU monopolization by a single container.
Failure to cPU Limits Are Set may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: CPUs={{ .HostConfig.NanoCpus }} CpuShares={{ .HostConfig.CpuShares }}'
docker run --cpus=1.0 --cpu-shares=512 <image>
Set a restart policy with a maximum retry count. Using always without a limit can mask crashes and consume resources during restart loops.
Failure to container Restart Policy Is Set Appropriately may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: RestartPolicy={{ .HostConfig.RestartPolicy.Name }} MaxRetry={{ .HostConfig.RestartPolicy.MaximumRetryCount }}'
docker run --restart=on-failure:5 <image>
5 — Docker Security Operations
▶Recommendations for operational security including secrets management and Docker Swarm mode security.
5.1 Secrets & Credentials
▶Use Docker secrets (Swarm mode), Docker BuildKit secrets, or external secrets managers (Vault, AWS Secrets Manager) instead of environment variables for sensitive data.
Failure to secrets Are Managed Using Docker Secrets or External Tools may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check for secrets in environment variables:
docker ps -q | xargs docker inspect --format \
'{{ .Name }}: {{ .Config.Env }}' | grep -iE 'password|secret|key|token'
# List Docker secrets (Swarm mode):
docker secret ls
# Docker Swarm secrets: echo "my-secret-value" | docker secret create db_password - # Docker BuildKit secrets: docker build --secret id=mysecret,src=./secret.txt . # In Dockerfile: RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
Do not hardcode passwords, API keys, or other credentials in docker-compose.yml files. Use environment variable substitution or Docker secrets.
Failure to no Hardcoded Credentials in Docker Compose Files may leave the Docker container platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
grep -rn 'password\|secret\|api_key\|token' docker-compose*.yml # Should not contain literal values
# Use .env file or environment variable substitution:
environment:
- DB_PASSWORD=${DB_PASSWORD}
# Or Docker secrets:
secrets:
db_password:
external: true
5.2 Swarm Mode Security
▶Enable Swarm autolock to encrypt the TLS key and Raft logs at rest. When autolock is enabled, a manager must provide the unlock key when restarting.
Without Swarm Auto-Lock enabled, the Docker container platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.
docker info | grep 'Is Manager' # If manager: docker swarm unlock-key # Should not return "no unlock key is set"
# Enable autolock: docker swarm update --autolock=true # Store the unlock key securely
Limit the number of Swarm manager nodes. Use an odd number (3 or 5) for fault tolerance while limiting the attack surface of manager-level access.
Unrestricted Swarm Manager Nodes could allow unauthorized users or processes to perform actions beyond their intended scope. Applying least-privilege principles to the Docker container platform is essential for defense in depth.
docker node ls --filter role=manager # Should be 3 or 5 (odd number for Raft consensus)
Demote excess managers: docker node demote <node-id>. Use 3 managers for small clusters, 5 for large ones.
Configure certificate rotation for Swarm node certificates. Short certificate lifetimes reduce the window for compromised certificates.
Misconfiguration of Certificate Rotation can lead to security gaps that may be exploited by attackers. A properly configured Docker container platform reduces exposure to both known vulnerabilities and configuration drift.
docker info | grep 'Expiry Duration' # Should be 90 days or less
docker swarm update --cert-expiry 720h