container security

Performing Docker Bench Security Assessment

Docker Bench for Security is an open-source script that checks dozens of common best practices around deploying Docker containers in production. Based on the CIS Docker Benchmark, it audits host configuration, Docker daemon settings, container images, runtime configurations, and security operations to generate a compliance report with pass/fail/warn results.

assessmentcis-benchmarkcontainersdockersecurity
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Docker Bench for Security is an open-source script that checks dozens of common best practices around deploying Docker containers in production. Based on the CIS Docker Benchmark, it audits host configuration, Docker daemon settings, container images, runtime configurations, and security operations to generate a compliance report with pass/fail/warn results.

When to Use

  • When conducting security assessments that involve performing docker bench security assessment
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • Docker Engine installed and running
  • Root or sudo access on Docker host
  • Docker Bench Security script or container image

Workflow

Step 1: Run Docker Bench Security

# Run as a container (recommended)
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/containerd:/usr/bin/containerd:ro \
  -v /usr/bin/runc:/usr/bin/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
 
# Run with JSON output
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 /dev/stdout 2>/dev/null | tee docker-bench-results.json
 
# Run specific sections only
docker run --rm --net host --pid host --userns host \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  docker/docker-bench-security -c container_images,container_runtime

Step 2: Interpret Results

[INFO] 1 - Host Configuration
[PASS] 1.1.1 - Ensure a separate partition for containers has been created
[WARN] 1.1.2 - Ensure only trusted users are allowed to control Docker daemon
[PASS] 1.1.3 - Ensure auditing is configured for the Docker daemon
 
[INFO] 2 - Docker daemon configuration
[FAIL] 2.1 - Run the Docker daemon as a non-root user
[PASS] 2.2 - Ensure network traffic is restricted between containers on the default bridge

Step 3: Remediate Common Failures

# Fix 2.2: Restrict inter-container communication
echo '{"icc": false}' | sudo tee /etc/docker/daemon.json
 
# Fix 2.17: Restrict containers from acquiring new privileges
echo '{"no-new-privileges": true}' | sudo tee -a /etc/docker/daemon.json
 
# Fix 5.3: Restrict Linux kernel capabilities
# Use --cap-drop ALL in docker run commands
 
# Fix 5.12: Mount container's root filesystem as read only
# Use --read-only flag in docker run commands
 
# Restart Docker daemon after configuration changes
sudo systemctl restart docker

Step 4: Automate Scheduled Assessments

# docker-compose for scheduled assessment
version: '3.8'
services:
  bench-security:
    image: docker/docker-bench-security
    network_mode: host
    pid: host
    userns_mode: host
    cap_add:
      - audit_control
    volumes:
      - /etc:/etc:ro
      - /var/lib:/var/lib:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./results:/results
    command: -l /results/bench-$(date +%Y%m%d).log
    deploy:
      restart_policy:
        condition: none

Validation Commands

# Verify remediation
docker run --rm docker/docker-bench-security 2>&1 | grep -E "(PASS|FAIL|WARN)" | sort | uniq -c
 
# Count results by type
docker run --rm docker/docker-bench-security 2>&1 | grep -c "PASS"
docker run --rm docker/docker-bench-security 2>&1 | grep -c "FAIL"
docker run --rm docker/docker-bench-security 2>&1 | grep -c "WARN"

References

Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.1 KB

API Reference — Performing Docker Bench Security Assessment

Libraries Used

  • subprocess: Run docker-bench-security container and docker inspect commands
  • json: Parse docker inspect JSON output

CLI Interface

python agent.py bench        # Run full docker-bench-security
python agent.py containers   # Check running container configurations

Core Functions

run_docker_bench()

Runs the docker/docker-bench-security container with host access for CIS benchmark checks.

parse_bench_output(output)

Parses [WARN], [PASS], [NOTE] lines into structured findings with sections.

check_container_configs()

Inspects all running containers for CIS Docker Benchmark violations.

CIS Checks Performed on Containers

Check CIS ID Severity
Privileged mode 5.4 CRITICAL
Host PID namespace 5.15 HIGH
Host network namespace 5.13 HIGH
Dangerous capabilities 5.3 HIGH
Running as root 4.1 MEDIUM
Sensitive host mounts 5.5 HIGH

Dependencies

Docker must be installed and accessible. No Python packages required beyond stdlib.

standards.md0.7 KB

Standards - Docker Bench Security Assessment

CIS Docker Benchmark v1.8.0 Sections

Section Area Checks
1 Host Configuration Partition, users, audit rules
2 Docker Daemon ICC, TLS, logging, seccomp, privileges
3 Docker Daemon Config Files File permissions and ownership
4 Container Images Non-root user, scanning, trusted images
5 Container Runtime Capabilities, rootfs, resources, privileges
6 Docker Security Operations Monitoring, CVE scanning

Scoring

  • PASS: Check meets CIS recommendation
  • FAIL: Check does not meet recommendation (remediation required)
  • WARN: Check requires manual verification
  • INFO: Informational, no scoring impact
workflows.md0.7 KB

Workflows - Docker Bench Security Assessment

Assessment Workflow

[Run Docker Bench] --> [Parse Results] --> [Prioritize FAIL findings]
        |                    |                      |
        v                    v                      v
  Initial baseline    Export JSON           Group by section
  assessment          for tracking          and severity
        |                    |                      |
        +--------------------+----------------------+
                             |
                             v
                [Create Remediation Plan]
                             |
                             v
                [Apply Fixes] --> [Re-run Assessment] --> [Compare Scores]

Scripts 2

agent.py5.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for performing Docker CIS Benchmark security assessment."""

import json
import argparse
import subprocess
from datetime import datetime


def run_docker_bench():
    """Run docker-bench-security and parse results."""
    cmd = [
        "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", "/var/lib:/var/lib:ro",
        "-v", "/var/run/docker.sock:/var/run/docker.sock:ro",
        "-v", "/usr/lib/systemd:/usr/lib/systemd:ro",
        "--label", "docker_bench_security",
        "docker/docker-bench-security", "-l", "/dev/stdout"
    ]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
        return parse_bench_output(result.stdout)
    except subprocess.TimeoutExpired:
        return {"error": "docker-bench-security timed out after 600s"}
    except FileNotFoundError:
        return {"error": "docker command not found"}


def parse_bench_output(output):
    """Parse docker-bench-security output into structured findings."""
    findings = []
    current_section = ""
    for line in output.split("\n"):
        line = line.strip()
        if not line:
            continue
        if line.startswith("[INFO]") and "- " in line and any(c.isdigit() for c in line[:20]):
            current_section = line.replace("[INFO]", "").strip()
        elif line.startswith("[WARN]"):
            findings.append({"level": "WARN", "section": current_section, "message": line.replace("[WARN]", "").strip()})
        elif line.startswith("[PASS]"):
            findings.append({"level": "PASS", "section": current_section, "message": line.replace("[PASS]", "").strip()})
        elif line.startswith("[NOTE]"):
            findings.append({"level": "NOTE", "section": current_section, "message": line.replace("[NOTE]", "").strip()})
    warn_count = sum(1 for f in findings if f["level"] == "WARN")
    pass_count = sum(1 for f in findings if f["level"] == "PASS")
    return {
        "timestamp": datetime.utcnow().isoformat(),
        "total_checks": len(findings),
        "warnings": warn_count,
        "passed": pass_count,
        "score_pct": round(pass_count / max(len(findings), 1) * 100, 1),
        "findings": findings,
    }


def check_container_configs():
    """Check running container configurations against CIS benchmarks."""
    try:
        result = subprocess.run(
            ["docker", "ps", "--format", "{{json .}}"],
            capture_output=True, text=True, timeout=30
        )
    except (subprocess.TimeoutExpired, FileNotFoundError):
        return {"error": "docker not available"}
    containers = []
    for line in result.stdout.strip().split("\n"):
        if not line:
            continue
        try:
            c = json.loads(line)
            containers.append(c)
        except json.JSONDecodeError:
            continue
    findings = []
    for container in containers:
        cid = container.get("ID", "")
        name = container.get("Names", "")
        inspect = _inspect_container(cid)
        if isinstance(inspect, dict) and "error" not in inspect:
            issues = _check_container_security(inspect, name)
            findings.append({"container": name, "id": cid, "issues": issues})
    return {"containers_checked": len(findings), "findings": findings}


def _inspect_container(container_id):
    try:
        result = subprocess.run(
            ["docker", "inspect", container_id], capture_output=True, text=True, timeout=10
        )
        data = json.loads(result.stdout)
        return data[0] if data else {}
    except Exception:
        return {"error": "inspect failed"}


def _check_container_security(inspect, name):
    issues = []
    host_config = inspect.get("HostConfig", {})
    if host_config.get("Privileged"):
        issues.append({"severity": "CRITICAL", "check": "5.4", "finding": "Container running in privileged mode"})
    if host_config.get("PidMode") == "host":
        issues.append({"severity": "HIGH", "check": "5.15", "finding": "Container shares host PID namespace"})
    if host_config.get("NetworkMode") == "host":
        issues.append({"severity": "HIGH", "check": "5.13", "finding": "Container shares host network namespace"})
    caps = host_config.get("CapAdd") or []
    dangerous_caps = {"SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE", "ALL"}
    added_dangerous = set(caps) & dangerous_caps
    if added_dangerous:
        issues.append({"severity": "HIGH", "check": "5.3", "finding": f"Dangerous capabilities added: {added_dangerous}"})
    config = inspect.get("Config", {})
    if config.get("User", "") in ("", "root", "0"):
        issues.append({"severity": "MEDIUM", "check": "4.1", "finding": "Container running as root user"})
    mounts = host_config.get("Binds") or []
    sensitive = ["/etc", "/var/run/docker.sock", "/proc", "/sys"]
    for mount in mounts:
        src = mount.split(":")[0]
        if any(src.startswith(s) for s in sensitive):
            issues.append({"severity": "HIGH", "check": "5.5", "finding": f"Sensitive host path mounted: {src}"})
    return issues


def main():
    parser = argparse.ArgumentParser(description="Docker CIS Benchmark Security Assessment")
    sub = parser.add_subparsers(dest="command")
    sub.add_parser("bench", help="Run docker-bench-security")
    sub.add_parser("containers", help="Check running container configurations")
    args = parser.parse_args()
    if args.command == "bench":
        result = run_docker_bench()
    elif args.command == "containers":
        result = check_container_configs()
    else:
        parser.print_help()
        return
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
process.py1.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Docker Bench Security Assessment Runner and Parser."""

import subprocess
import json
import sys
import re

def run_docker_bench():
    """Run Docker Bench Security and parse results."""
    cmd = [
        "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"
    ]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
        output = result.stdout + result.stderr
    except (subprocess.TimeoutExpired, FileNotFoundError) as e:
        print(f"[!] Failed to run Docker Bench: {e}")
        sys.exit(1)

    results = {"PASS": [], "FAIL": [], "WARN": [], "INFO": []}
    for line in output.split("\n"):
        for status in ["PASS", "FAIL", "WARN", "INFO"]:
            if f"[{status}]" in line:
                check = line.strip()
                results[status].append(check)
                break

    print(f"\n{'='*60}")
    print("DOCKER BENCH SECURITY RESULTS")
    print(f"{'='*60}")
    print(f"PASS: {len(results['PASS'])}")
    print(f"FAIL: {len(results['FAIL'])}")
    print(f"WARN: {len(results['WARN'])}")
    print(f"INFO: {len(results['INFO'])}")

    total = len(results['PASS']) + len(results['FAIL'])
    if total > 0:
        score = (len(results['PASS']) / total) * 100
        print(f"Score: {score:.1f}%")

    if results["FAIL"]:
        print(f"\nFAILED CHECKS:")
        for f in results["FAIL"]:
            print(f"  {f}")

    with open("docker_bench_results.json", "w") as fh:
        json.dump(results, fh, indent=2)
    print(f"\n[*] Results saved to docker_bench_results.json")

if __name__ == "__main__":
    run_docker_bench()

Assets 1

template.mdtext/markdown · 0.4 KB
Keep exploring