Skip to main content
CleanStart

Knowledge Hub

CIS Docker Benchmark Compliance: Container Hardening

Related Fundamentals: CIS controls enforce the security best practices described in Container Security Best Practices. Understanding the scope distinction in Container Scope vs Kernel Scope helps clarify which CIS controls apply at each layer.

Implementing CIS Docker Benchmark Controls

The Center for Internet Security (CIS) Docker Benchmark specifies 94 controls for securing Docker containers. CleanStart images pass CIS compliance automatically through hardened base images and automated checks.

CIS Controls Overview

Control Groups

Group

Count

Focus

CleanStart Support

Host Configuration

5

Docker daemon, kernel

Pre-configured

Docker Daemon

13

Configuration, logging

Pre-configured

Docker Images

10

Build, registry, base

Automated checks

Containers

42

Runtime, capabilities

Policy enforcement

Kubernetes

24

Orchestration

Policy enforcement

CleanStart handles host/daemon/image controls automatically; containers enforce via policies.

Critical CIS Controls

Image Security (CIS 4.x)

# CIS 4.1: Ensure a user is created for running containers# CleanStart ensures all images have non-root user FROM ubuntu:24.04RUN useradd -m -u 1000 appuserUSER appuser  # Run as non-root

Container Runtime (CIS 5.x)

# CIS 5.1: Verify CPU limits are setspec:  containers:  - name: myapp    resources:      limits:        cpu: "1"        memory: "512Mi"      requests:        cpu: "100m"        memory: "128Mi" # CIS 5.2: Set memory limits# (shown above) # CIS 5.3: Set network traffic rulesnetworkPolicy:  podSelector:    matchLabels:      app: myapp  policyTypes:  - Ingress  - Egress  ingress:  - from:    - namespaceSelector:        matchLabels:          name: production    ports:    - protocol: TCP      port: 8080  egress:  - to:    - namespaceSelector:        matchLabels:          name: production    ports:    - protocol: TCP      port: 443

Container Capabilities (CIS 5.28)

# CIS 5.28: Disable unnecessary kernel capabilitiesspec:  securityContext:    capabilities:      drop:      - ALL  # Drop all capabilities      add:      - NET_BIND_SERVICE  # Only add what's needed     readOnlyRootFilesystem: true  # CIS 5.4    runAsNonRoot: true  # CIS 5.1    runAsUser: 1000  # CIS 5.2

CleanStart CIS Automation

Automated CIS Checks

# Check image for CIS compliancecleanimg-init --cis-check --image myapp:1.0.0 # Output:# CIS 4.1: Non-root user configured# CIS 4.2: Container base image scanned# CIS 4.3: Image signed (missing signature)# CIS 4.4: Metadata labels present# CIS 4.5: Health check defined# Summary: 19/20 controls passed (95%)# Recommendation: Add image signature

Deploy with CIS Enforcement

# Kubernetes admission controller enforces CISapiVersion: constraints.gatekeeper.sh/v1beta1kind: K8sCISDockerBenchmarkmetadata:  name: cis-enforcementspec:  match:    kinds:    - apiGroups: [""]      kinds: ["Pod"]  parameters:    severity: high    enforceAll: true    exemptNamespaces: ["kube-system"]

CIS Host and Daemon Controls

Docker Daemon Security (Pre-Configured)

CleanStart assumes these are configured on the host:

# CIS 2.1: Run daemon as non-rootps aux | grep dockerd# root    1234  0.0  0.5 1234567 56789 ?  Ss  14:00  0:00 /usr/bin/dockerd # CIS 2.2: Restrict Docker socket permissionsls -l /var/run/docker.sock# srw-rw----  1 root docker 0 Oct  4 14:00 /var/run/docker.sock # CIS 2.3: Enable user namespace remappingcat /etc/docker/daemon.json | jq '.userns_mode'# "host"  (or use remapping for security) # CIS 2.4: Enable Apparmordocker inspect myapp | jq '.[0].AppArmorProfile'# "docker-default" # CIS 2.5: Enable SELinuxgetenforce# Enforcing  (if available)

Image Hardening Specifics

Minimal Base Image

# CIS 4.2: Use minimal base imagesFROM alpine:3.19  # ~5MB, minimal attack surface# Instead of: FROM ubuntu:24.04  # ~70MB, more surface # CIS 4.3: Scan base image for vulnerabilities# (CleanStart does this automatically) # CIS 4.4: Add security labelsLABEL security.cis="4.2"LABEL maintainer="security@company.com"LABEL description="Minimal, hardened app image" # CIS 4.5: Add health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \  CMD /usr/local/bin/healthcheck.sh || exit 1

Non-Root User Enforcement

# CIS 4.1: Create non-root userRUN useradd -m -u 1000 appuserUSER appuser # All subsequent commands run as appuser (UID 1000)# NOT root (UID 0) # Verify in DockerfileRUN whoami  # Output: appuser

Read-Only Root Filesystem

# CIS 5.4: Configure read-only root filesystem# Requires application to write only to /tmp or /var/tmp FROM alpine:3.19 # Create writable directoriesRUN mkdir -p /tmp /var/tmpRUN chmod 1777 /tmp /var/tmp # Application runs with read-only root# Pod spec enforces: readOnlyRootFilesystem: true

Runtime CIS Enforcement

Pod Security Standards (Kubernetes)

# Kubernetes Pod Security Standards (replaces deprecated PSP)apiVersion: policy.k8s.io/v1alpha1kind: PodSecurityPolicymetadata:  name: cis-restrictedspec:  privileged: false  # CIS 5.25  allowPrivilegeEscalation: false  # CIS 5.7  requiredDropCapabilities:  - ALL  # CIS 5.28  volumes:  - 'configMap'  - 'emptyDir'  - 'secret'  hostNetwork: false  # CIS 5.21  hostIPC: false  # CIS 5.22  hostPID: false  # CIS 5.23  runAsUser:    rule: 'MustRunAsNonRoot'  # CIS 5.1  seLinux:    rule: 'MustRunAs'  # CIS 5.24  fsGroup:    rule: 'RunAsAny'  readOnlyRootFilesystem: true  # CIS 5.4

Network Policies (CIS 5.3)

# Restrict network traffic (Kubernetes)apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:  name: myapp-network-policyspec:  podSelector:    matchLabels:      app: myapp  policyTypes:  - Ingress  - Egress  ingress:  - from:    - podSelector:        matchLabels:          app: frontend    ports:    - protocol: TCP      port: 8080  egress:  - to:    - podSelector:        matchLabels:          app: database    ports:    - protocol: TCP      port: 5432  - to:  # Allow DNS    - namespaceSelector: {}    ports:    - protocol: UDP      port: 53

CIS Compliance Mapping

CIS Control

CleanStart Implementation

4.1 Non-root user

Automated in Dockerfile

4.2 Minimal base

Alpine/distroless images

4.3 Vulnerability scanning

Automated with Grype

4.4 Metadata labels

Automated injection

5.1 CPU limits

Kubernetes policy

5.4 Read-only filesystem

Pod config template

5.7 Privilege escalation

Security context policy

5.28 Capabilities

Drop ALL in pod spec

Testing CIS Compliance

Manual CIS Audit

# Download CIS Docker Benchmark reference# Run manual checks # Check 4.1: Non-root userdocker run myapp:1.0.0 whoami# Output: appuser (not root) # Check 4.2: Minimal basedocker images myapp:1.0.0 --format "{{.Size}}"# Should be < 50MB # Check 4.5: Health checkdocker inspect myapp:1.0.0 | jq '.Config.Healthcheck'# Should show health check configuration

Automated Audit Tools

# Use CIS-CAT or Docker Bench Security # Docker Bench Security (free)docker run --rm --net host --pid host \  --userns host --cap-add audit_control \  -v /var/lib:/var/lib \  -v /var/run/docker.sock:/var/run/docker.sock \  -v /etc:/etc:ro \  docker/docker-bench-security # Output shows CIS controls and pass/fail

Common CIS Failures and Fixes

Failure: Running as Root

# BADFROM ubuntu:24.04COPY app /appENTRYPOINT ["/app/myapp"]# Runs as root by default # GOODFROM ubuntu:24.04RUN useradd -m -u 1000 appuserCOPY --chown=appuser:appuser app /appUSER appuser  # Must be before ENTRYPOINTENTRYPOINT ["/app/myapp"]

Failure: Unnecessary Capabilities

# BADspec:  securityContext:    capabilities:      add:      - ALL  # Adds all capabilities # GOODspec:  securityContext:    capabilities:      drop:      - ALL  # Drop all first      add:      - NET_BIND_SERVICE  # Add only what's needed

Failure: No Resource Limits

# BADspec:  containers:  - name: myapp    image: myapp:1.0.0    # No limits - can consume all resources # GOODspec:  containers:  - name: myapp    image: myapp:1.0.0    resources:      limits:        cpu: "2"        memory: "1Gi"      requests:        cpu: "100m"        memory: "128Mi"

CIS Benchmark Compliance Report

# Generate CIS compliance reportcleanimg-init --cis-report --image myapp:1.0.0 --format html --output cis-report.html # Report shows:# - Each control (4.1, 4.2, etc.)# - Pass/fail status# - Remediation steps# - Risk rating# - Compliance percentage (95/100 = 95%)

See Also

STIG Hardening: stig-hardening.md — DISA security hardening. OpenSCAP: openscap-reference.md — Automated compliance scanning. FedRAMP: ../regulatory/fedramp-high.md — Government compliance.