SockguardSockguard

CIS Docker Benchmark

How sockguard's container_create body inspection maps to the inspectable subset of the CIS Docker Benchmark v1.6.0 — and the cis-docker-benchmark.yaml preset that turns it on.

The CIS Docker Benchmark v1.6.0 is the de-facto compliance baseline for Docker deployments. It catalogues 117 controls across the host, the daemon, images, runtime, operations, and Swarm. Sockguard sits at the API boundary, so the controls it can enforce are the runtime ones in Section 5: when a docker run would violate them, sockguard rejects the request with 403 before dockerd executes it. The CIS posture becomes an admission gate, not just an audit finding.

This page maps each inspectable Section 5 control to the sockguard knob that enforces it. The ready-made cis-docker-benchmark.yaml preset turns every one of them on at once.

Quick start

docker run -d \
  --name sockguard \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /etc/sockguard/cis-docker-benchmark.yaml:/etc/sockguard/config.yaml:ro \
  -v sockguard-sock:/run/sockguard \
  ghcr.io/codeswhat/sockguard:latest

The preset is bundled in the container image at /etc/sockguard/cis-docker-benchmark.yaml. Mount it as config.yaml to activate.

A workload that violates any of the mapped controls gets a 403 with the deny reason naming the specific knob:

{
  "message": "request denied by sockguard policy"
}

(The preset uses deny_verbosity: minimal so the response never echoes the violating field; the structured access log in Observability records the full deny reason.)

What sockguard enforces

CIS controlDescriptionSockguard knob
5.3Linux kernel capabilities restrictedallowed_capabilities: [] + require_drop_all_capabilities: trueCapAdd must be empty, CapDrop must include ALL
5.4Privileged containers not usedallow_privileged: false — rejects HostConfig.Privileged: true
5.5Sensitive host directories not mountedallowed_bind_mounts: [] — every host-path bind must be on the allowlist; default-empty rejects all binds
5.9Host network namespace not sharedallow_host_network: false — rejects NetworkMode: "host"
5.10Memory usage limitedrequire_memory_limit: trueHostConfig.Memory must be non-zero
5.11CPU priority setrequire_cpu_limit: true — at least one of CPUShares, CPUQuota, NanoCpus must be set
5.12Container root filesystem mounted read-onlyrequire_readonly_rootfs: trueHostConfig.ReadonlyRootfs must be true
5.15Host PID namespace not sharedallow_host_pid: false — rejects PidMode: "host"
5.16Host IPC namespace not sharedallow_host_ipc: false — rejects IpcMode: "host"
5.17Host devices not directly exposedallowed_devices: [], allow_all_devices: falseHostConfig.Devices must be empty (allowlist host paths for genuine GPU/HW use)
5.21Default seccomp profile not disableddeny_unconfined_seccomp: true — rejects SecurityOpt: ["seccomp=unconfined"]
5.22Docker exec without --privilegedrequest_body.exec.allow_privileged: false (when exec is allowed by rule)
5.23Docker exec without --user=rootrequest_body.exec.allow_root_user: false (when exec is allowed by rule)
5.25Acquiring additional privileges restrictedrequire_no_new_privileges: trueHostConfig.SecurityOpt must include no-new-privileges:true
5.28PIDs cgroup limit usedrequire_pids_limit: trueHostConfig.PidsLimit must be non-zero
5.30Host user namespace not sharedallow_host_userns: false — rejects UsernsMode: "host"
5.31Docker socket not mounted inside containersSatisfied structurally by deploying sockguard — workloads see the proxy socket, not the real /var/run/docker.sock

The preset wires every row above to its CIS-compliant default. Edit the preset to widen a knob only when a workload genuinely requires it; that edit is itself the auditable record of why your CIS posture diverges from the benchmark.

Beyond Section 5 — controls sockguard influences

CIS controlDescriptionHow sockguard contributes
2.6TLS authentication for Docker daemonmTLS on the sockguard TCP listener (see Configuration → mTLS) replaces direct daemon TLS for in-cluster consumers
4.5Content trust for Dockerrequest_body.container_create.image_trust.mode: enforce verifies cosign signatures on image references before the create reaches the daemon
5.22/5.23Exec hardeningWhen a rule permits exec, the request_body.exec block applies the same admission gates documented above
7.xSwarm controls (operations)This preset denies the entire /swarm/**, /services/**, /nodes/**, /configs/**, /secrets/** surface — meeting 7.1–7.10 by exclusion. Re-enable per rule for clusters that actually use Swarm

What sockguard cannot enforce

These controls live above or below the Docker Engine API. Sockguard does not see them, so the preset cannot help. Track them with the recommended companion tool.

CIS sectionExamplesRecommended check
1.x — Host configurationOS hardening, audit daemon, mount pointsdocker-bench-security
2.x — Daemon configurationlive-restore, default logging driver, default ulimit, registry trustdockerd flags + docker-bench-security
3.x — Daemon config filesfile permissions on /etc/docker/daemon.json, key/cert ownershipfilesystem audit
4.x — Container imagesbase image scanning, HEALTHCHECK, image freshness (4.6, 4.7)Trivy or Grype on the image, registry-side controls
5.x runtime — uninspectable5.6 SSH not running in container (image-level), 5.7/5.8 ports (network-level), 5.13 traffic binding, 5.14 restart policy, 5.18 ulimit override, 5.19 mount propagation, 5.20 UTS namespace, 5.24 cgroup usage, 5.26 healthcheck at runtime, 5.27 updated image, 5.29 default bridgeimage scanner + dockerd flags + container-runtime audit
6.x — Security operationsimage lifecycle policyregistry-side governance

For a complete CIS posture, run the preset above plus docker-bench-security periodically against the host. The two are complementary: sockguard catches runtime violations as they happen, docker-bench-security catches configuration drift on the host and daemon.

Verifying the posture

A two-step verification per workload:

  1. Negative test. Try to run a non-compliant container through sockguard. It must come back 403:

    curl -X POST --unix-socket /run/sockguard/sockguard.sock \
      -H 'Content-Type: application/json' \
      -d '{"Image":"alpine","HostConfig":{"Privileged":true}}' \
      http://localhost/containers/create
    # → HTTP/1.1 403 Forbidden
  2. Positive test. Run a compliant container. It must succeed with the usual 201:

    curl -X POST --unix-socket /run/sockguard/sockguard.sock \
      -H 'Content-Type: application/json' \
      -d '{
            "Image":"alpine",
            "HostConfig":{
              "ReadonlyRootfs":true,
              "Memory":67108864,
              "PidsLimit":50,
              "CpuShares":256,
              "CapDrop":["ALL"],
              "SecurityOpt":["no-new-privileges:true"]
            }
          }' \
      http://localhost/containers/create
    # → HTTP/1.1 201 Created

The structured access log records both with the matching rule and (on deny) the violated knob; pipe it into your SIEM as the auditable evidence that the CIS posture is live, not just documented.

Customizing the preset

The preset's body-inspection block is intentionally verbose — every CIS- mapped knob is set explicitly even when the value equals the secure default. Editing the file is therefore the canonical place to record why your deployment diverges from CIS:

request_body:
  container_create:
    # CIS 5.5: production workload needs /srv/data mounted. Diverges
    # from the benchmark intentionally — approved 2026-05-20 by
    # security.
    allowed_bind_mounts:
      - "/srv/data:/data"

A git diff of the preset is the audit trail. If the file matches the shipped baseline, the deployment is CIS-aligned by inspection.

On this page