Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Hardening Docker containers for production involves applying security best practices aligned with CIS Docker Benchmark v1.8.0 to minimize attack surface, prevent privilege escalation, and enforce leas
.claude/skills/hardening-docker-containers-for-production/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | — | — |
| case-18 | ✗→✓ | ▲ Improved | — | — |
| case-09 | ✓→✓ | = Same ✓ | — | — |
| case-14 | ✗→✗ | = Same ✗ | — | — |
| case-22 | ✗→✗ | = Same ✗ | — | — |
Hardening Docker containers for production involves applying security best practices aligned with CIS Docker Benchmark v1.8.0 to minimize attack surface, prevent privilege escalation, and enforce least-privilege principles across Docker daemon, images, containers, and runtime configurations.
dockerfile# Use specific digest for reproducibility FROM python:3.12-slim@sha256:abc123... AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir --user -r requirements.txt # Production stage - minimal image FROM gcr.io/distroless/python3-debian12 # Copy only necessary artifacts COPY --from=builder /root/.local /root/.local COPY --from=builder /app /app WORKDIR /app # Create non-root user USER 65534:65534 # Set read-only filesystem expectation LABEL org.opencontainers.image.source="https://github.com/org/app" ENTRYPOINT ["python", "app.py"]
json{ "icc": false, "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "live-restore": true, "userland-proxy": false, "no-new-privileges": true, "default-ulimits": { "nofile": { "Name": "nofile", "Hard": 64000, "Soft": 64000 }, "nproc": { "Name": "nproc", "Hard": 1024, "Soft": 1024 } }, "seccomp-profile": "/etc/docker/seccomp-default.json", "tls": true, "tlscacert": "/etc/docker/tls/ca.pem", "tlscert": "/etc/docker/tls/server-cert.pem", "tlskey": "/etc/docker/tls/server-key.pem", "tlsverify": true }
bashdocker run -d \ --name production-app \ --read-only \ --tmpfs /tmp:rw,noexec,nosuid,size=100m \ --tmpfs /var/run:rw,noexec,nosuid,size=10m \ --cap-drop ALL \ --cap-add NET_BIND_SERVICE \ --security-opt no-new-privileges:true \ --security-opt seccomp=/etc/docker/seccomp-default.json \ --security-opt apparmor=docker-default \ --pids-limit 100 \ --memory 512m \ --memory-swap 512m \ --cpus 1.0 \ --user 65534:65534 \ --network custom-bridge \ --restart on-failure:3 \ --health-cmd "curl -f http://localhost:8080/health || exit 1" \ --health-interval 30s \ --health-timeout 10s \ --health-retries 3 \ myapp:latest
bashexport DOCKER_CONTENT_TRUST=1 export DOCKER_CONTENT_TRUST_SERVER=https://notary.example.com # Sign and push image docker trust sign myregistry.com/myapp:v1.0.0 # Verify image signature before pull docker trust inspect --pretty myregistry.com/myapp:v1.0.0
bash# Add audit rules for Docker files and directories cat >> /etc/audit/rules.d/docker.rules << 'EOF' -w /usr/bin/docker -k docker -w /var/lib/docker -k docker -w /etc/docker -k docker -w /lib/systemd/system/docker.service -k docker -w /lib/systemd/system/docker.socket -k docker -w /etc/default/docker -k docker -w /etc/docker/daemon.json -k docker -w /usr/bin/containerd -k docker -w /usr/bin/runc -k docker EOF systemctl restart auditd
bash# Run Docker Bench Security 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 \ docker/docker-bench-security # Lint Dockerfile hadolint Dockerfile # Lint built image dockle myapp:latest # Verify no containers running as root docker ps -q | xargs docker inspect --format '{{.Id}}: User={{.Config.User}}'
| Control | Implementation | CIS Section | |---------|---------------|-------------| | Non-root user | USER instruction in Dockerfile | 4.1 | | Read-only rootfs | --read-only flag | 5.12 | | Drop capabilities | --cap-drop ALL | 5.3 | | Resource limits | --memory, --cpus, --pids-limit | 5.10 | | No new privileges | --security-opt no-new-privileges | 5.25 | | Content trust | DOCKER_CONTENT_TRUST=1 | 4.5 | | TLS for daemon | daemon.json TLS config | 2.6 | | Audit logging | auditd rules | 1.1 |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-23 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.