from raw report to prioritized hardening
Docker Bench Security automatically checks host, daemon and running containers against the CIS Docker Benchmark and produces a structured report within minutes. Reading that output correctly, prioritizing it and wiring it into the CI pipeline turns a one time audit into a continuous security process instead of an ignored PDF file.
Table of Contents
- 1. What Docker Bench Security checks and why it matters
- 2. Installation and a first run against the host
- 3. Understanding the structure of the CIS Docker Benchmark
- 4. Checking and hardening host configuration
- 5. Securing the Docker daemon configuration
- 6. Interpreting container and image checks correctly
- 7. Recognizing false positives and defining a baseline
- 8. Automating Docker Bench Security in CI/CD
- 9. Docker Bench Security compared to other tools
- 10. Summary
- 11. FAQ
1. What Docker Bench Security checks and why it matters
Docker Bench Security is a shell script maintained by Docker Inc. and the community that checks the host, the running daemon and all active containers against the CIS Docker Benchmark. Instead of manually looking up individual settings, Docker Bench Security produces a structured report within minutes, marking each of roughly a hundred individual checks as PASS, WARN or INFO. The tool does not replace deep image analysis, but it is the fastest way to get a realistic overview of a Docker host's security posture.
The real value of Docker Bench Security lies in the fact that it answers configuration questions that are often overlooked in practice: is audit logging enabled on the daemon? Are container permissions unnecessarily broad? Is the Docker socket reachable without protection? These questions do not concern a single image but the entire operating environment, and that is exactly where Docker Bench Security steps in.
In practice, Docker Bench Security is often run once before an audit or certification and then forgotten. That is a mistake, because configuration drift is the rule rather than the exception in Docker environments. A new team member resets a daemon feature flag, a deployment script forgets a security setting, and the security posture degrades quietly. The following sections show how Docker Bench Security is installed, interpreted, prioritized and permanently embedded into operations.
2. Installation and a first run against the host
Docker Bench Security itself runs as a container with far reaching access to the host, because it needs to check exactly those host properties. The script requires access to the Docker socket, to `/etc`, to `/usr/bin/docker` and to the daemon's systemd unit files. Without these mounts, Docker Bench Security can only actually perform a fraction of the checks and reports the remaining ones as INFO instead of a real result.
The first run should happen on a representative host, not on an isolated test machine with a different configuration. Only then does Docker Bench Security deliver results that actually reflect the production state. The script writes its report to the console by default, but it can also be exported as JSON, which matters greatly for later automation.
#!/usr/bin/env bash
# Run Docker Bench Security against the local host
set -euo pipefail
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST="$DOCKER_CONTENT_TRUST" \
-v /etc:/etc:ro \
-v /usr/bin/docker-containerd:/usr/bin/docker-containerd:ro \
-v /usr/bin/docker-runc:/usr/bin/docker-runc:ro \
-v /usr/lib/systemd:/usr/lib/systemd:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--label docker_bench_security \
docker/docker-bench-security > bench-report.log
# Extract only WARN lines for a quick first triage
grep '\[WARN\]' bench-report.log | sort | uniq -c | sort -rn
A common beginner mistake is starting Docker Bench Security without `--net host` and `--pid host`. Without these flags the script only sees its own isolated namespace instead of the host processes, and a large share of the runtime checks come back as INFO instead of a reliable result. Anyone who wants to seriously evaluate the report should always use the full mount and namespace configuration from the official documentation.
3. Understanding the structure of the CIS Docker Benchmark
The CIS Docker Benchmark that Docker Bench Security maps onto is divided into seven main sections: host configuration, Docker daemon configuration, daemon configuration files, container images and build files, container runtime, Docker security operations and Docker Swarm configuration. Each section contains numbered individual checks, which appear in the Docker Bench Security report under the same numbering, making it easy to look them up in the official CIS documentation.
Not every check is equally relevant for every environment. A check about Docker Swarm configuration provides no practical value in pure Compose or Kubernetes setups and should be classified accordingly. Docker Bench Security does not automatically distinguish between relevant and irrelevant checks for a given architecture, that assessment remains the task of the team reading the report. Whoever ignores this context wastes time fixing findings that do not even apply in their own environment.
4. Checking and hardening host configuration
The first section of the CIS benchmark that Docker Bench Security queries concerns host configuration independent of Docker itself: a separate partition for container data, a current kernel version, enabled auditing for Docker binaries and directories. These checks look generic at first glance, but they are the foundation on which every container isolation is built. An outdated kernel without the relevant security patches makes even the best container configuration attackable.
Particularly important is the check for auditing `/usr/bin/docker`, `/var/lib/docker`, `/etc/docker` and the corresponding systemd unit files through `auditd`. Without these audit rules, an unauthorized change to the Docker configuration goes unnoticed until damage has already occurred. Docker Bench Security consistently marks missing audit rules as WARN, because they are forensically decisive as soon as an incident needs to be investigated.
#!/usr/bin/env bash
# Add auditd rules that Docker Bench Security checks for (host hardening)
set -euo pipefail
cat >> /etc/audit/rules.d/docker.rules <<'EOF'
-w /usr/bin/docker -p wa -k docker
-w /var/lib/docker -p wa -k docker
-w /etc/docker -p wa -k docker
-w /lib/systemd/system/docker.service -p wa -k docker
-w /lib/systemd/system/docker.socket -p wa -k docker
-w /etc/default/docker -p wa -k docker
-w /etc/docker/daemon.json -p wa -k docker
-w /usr/bin/containerd -p wa -k docker
-w /usr/sbin/runc -p wa -k docker
EOF
augenrules --load
systemctl restart auditd
5. Securing the Docker daemon configuration
The second major block of checks in Docker Bench Security concerns the running daemon configuration: is TLS encrypted access to the Docker socket active, if it is reachable over the network at all? Is live restore enabled so containers survive a daemon restart? Is user namespace remapping configured to decouple root inside a container from real root on the host? Each of these questions corresponds to a concrete entry in `/etc/docker/daemon.json`, which Docker Bench Security checks specifically.
Particularly critical is the check for an unprotected TCP socket. A Docker daemon listening on `tcp://0.0.0.0:2375` without TLS grants any network participant full root rights on the host, because any container can be started with `--privileged`. Docker Bench Security consistently classifies this finding as a critical WARN, and rightly so: in practice this is one of the most common ways compromised Docker hosts are found in the wild.
{
"live-restore": true,
"userns-remap": "default",
"no-new-privileges": true,
"icc": false,
"log-driver": "journald",
"log-opts": { "max-size": "10m", "max-file": "3" },
"userland-proxy": false,
"tls": true,
"tlsverify": true,
"tlscacert": "/etc/docker/certs/ca.pem",
"tlscert": "/etc/docker/certs/server-cert.pem",
"tlskey": "/etc/docker/certs/server-key.pem"
}
6. Interpreting container and image checks correctly
The container runtime section is usually the longest WARN block on a first Docker Bench Security run, because it checks every running container against more than twenty criteria: an active AppArmor or SELinux profile, no privilege escalation allowed, no mounted sensitive host paths, no access to the Docker socket inside the container itself, bounded memory and CPU resources. A single container can easily generate ten or more WARN entries here.
What matters is not to work through these findings uniformly, but to sort them by attack surface. A container without a defined memory limit is an operational risk, but rarely a direct security incident. A container with a mounted Docker socket (`-v /var/run/docker.sock:/var/run/docker.sock`), on the other hand, is a direct path to full host compromise, because that container can start any other container with any permissions. Docker Bench Security reports both cases as WARN, but they are not comparable in terms of prioritization.
# Typical Docker Bench Security output for the container runtime section
[WARN] 5.1 - Ensure AppArmor Profile is Enabled
[WARN] 5.4 - Ensure privileged containers are not used
[WARN] 5.6 - Ensure ssh is not run within containers
[WARN] 5.9 - Ensure the host's network namespace is not shared
[WARN] 5.10 - Ensure memory usage for container is limited
[WARN] 5.31 - Ensure the Docker socket is not mounted inside any containers
# Prioritize by real attack surface, not just WARN count
for cid in $(docker ps -q); do
docker inspect "$cid" | jq -r '.[0].Mounts[].Source' | grep -q docker.sock \
&& echo "[CRITICAL] Container $cid has the Docker socket mounted"
done
7. Recognizing false positives and defining a baseline
Not every WARN from Docker Bench Security is a real risk in every environment. Some checks assume Docker Swarm operation and are irrelevant for pure Compose deployments, others concern legacy options such as the unprotected userland proxy, which is disabled anyway in modern setups. Whoever weighs every check equally quickly loses overview and starts ignoring reports instead of using them.
The pragmatic approach is to define a documented baseline: which checks are deliberately marked as accepted risk, with reasoning and an owner, and which must be at PASS on every Docker Bench Security run. This baseline belongs in the repository, not in one person's head, so new team members can trace why certain WARN findings are consciously accepted.
8. Automating Docker Bench Security in CI/CD
A one time audit loses its value as soon as infrastructure changes. The sustainable approach is to run Docker Bench Security regularly against production like hosts and compare results against the defined baseline. If a new run deviates from the baseline, because a previously PASS marked check suddenly reports WARN, that is a clear signal of configuration drift that should trigger an alert.
The JSON output of Docker Bench Security can be filtered with `jq` for new or changed findings instead of manually reading the entire report on every run. In a scheduled pipeline, for example a weekly cron job against the production hosts, a one time compliance proof turns into a continuous control mechanism.
#!/usr/bin/env bash
# Compare Docker Bench Security JSON output against an accepted baseline
set -euo pipefail
docker run --rm --net host --pid host --userns 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 -l /tmp/bench.json -j > /dev/null
# Fail the pipeline if a new WARN appears that is not in the accepted baseline
new_warns=$(jq -r '.tests[].results[] | select(.result=="WARN") | .id' /tmp/bench.json \
| grep -vFf accepted-baseline.txt || true)
if [[ -n "$new_warns" ]]; then
echo "[ALERT] New Docker Bench Security findings outside baseline:" >&2
echo "$new_warns" >&2
exit 1
fi
echo "[OK] No new findings outside the accepted Docker Bench Security baseline"
9. Docker Bench Security compared to other tools
Docker Bench Security covers host and daemon configuration excellently, but does not replace image vulnerability analysis or runtime anomaly detection. The following table places the tool against other common approaches so it becomes clear which gaps additional tools need to close.
| Tool | Checks | Runs when | Complements Docker Bench Security |
|---|---|---|---|
| Docker Bench Security | Host, daemon, config files, runtime | Manual or scheduled | Foundation for every other tool |
| Trivy / Grype | Known CVEs in image layers | Build time / CI | Yes, different layer (image instead of host) |
| Falco | Anomalous runtime behavior | Continuous, live | Yes, covers attacks after startup |
| Manual code review | Dockerfile anti patterns | Pull request | Yes, catches root causes earlier |
Docker Bench Security is therefore not a replacement, but the foundation: without a properly hardened host and daemon, even the best scanned image runs on unsafe ground. The combination of Docker Bench Security for host and daemon, Trivy or Grype for images, and Falco for runtime covers the three relevant layers of container security completely.
Mironsoft
Container security audits and Docker hardening
How secure is your Docker infrastructure really?
We run Docker Bench Security audits, prioritize findings by real attack surface, and harden host, daemon and container configuration systematically instead of just checking off compliance reports.
CIS audit
Docker Bench Security runs with full findings prioritization
Daemon hardening
Configure TLS, user namespace remapping and audit logging production ready
CI integration
Build continuous audits with baseline comparison into your pipeline
10. Summary
Docker Bench Security is the fastest entry point into a structured CIS audit for Docker hosts. The tool checks host configuration, daemon settings, configuration files and container runtime against roughly a hundred documented checks and delivers a prioritizable report instead of vague guesses. What matters is not to treat the report as a one time exercise, but to define a documented baseline and detect deviations automatically.
Docker Bench Security replaces neither image scanning nor runtime threat detection, but it forms the foundation both build on. A hardened host with a correctly configured daemon reduces the attack surface before a single image is even checked. Combined with regular CI runs, the script turns into a continuous control mechanism instead of a one time compliance proof.
Docker Bench Security — The essentials at a glance
Installation
Runs as a container with `--net host --pid host` and access to Docker socket, `/etc` and systemd units, otherwise runtime checks stay incomplete.
Scope
Seven CIS sections: host, daemon, configuration files, images, runtime, security operations, Swarm.
Prioritization
Not every WARN is equally critical: a mounted Docker socket outranks a missing memory limit by far.
Automation
JSON export plus baseline comparison with `jq` in a scheduled pipeline detects configuration drift automatically.