# 140 Claude A2ba6000

> Docker Security Rules for Claude Code

- Skill: `tools-only/140-claude-a2ba6000` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/140-claude-a2ba6000`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/140-claude-a2ba6000/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/tools-only/140-claude-a2ba6000

---

# Docker Security Rules for Claude Code

These rules guide Claude Code to generate secure Docker configurations, Dockerfiles, and container deployments. Apply these rules when creating or modifying Docker-related files.

---

## Rule: Minimal Base Images

**Level**: `strict`

**When**: Creating Dockerfiles or selecting base images

**Do**: Use minimal base images appropriate for your application
```dockerfile
# Best for compiled languages (Go, Rust, C++)
FROM scratch AS runtime
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/binary /binary
USER 65534:65534
ENTRYPOINT ["/binary"]

# Best for most applications - Google's distroless
FROM gcr.io/distroless/base-debian12:nonroot AS runtime
COPY --from=builder /app /app
USER nonroot:nonroot
ENTRYPOINT ["/app/server"]

# Good for interpreted languages requiring packages
FROM python:3.12-alpine AS runtime
RUN apk add --no-cache ca-certificates tini && \
    rm -rf /var/cache/apk/* /tmp/*
USER nobody:nobody
ENTRYPOINT ["/sbin/tini", "--"]

# For Java applications
FROM gcr.io/distroless/java21-debian12:nonroot
COPY --from=builder /app/app.jar /app/app.jar
USER nonroot:nonroot
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

**Don't**: Use full OS images or unnecessarily large base images
```dockerfile
# Vulnerable: Full Ubuntu with unnecessary tools
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
    python3 python3-pip \
    curl wget vim nano \
    net-tools iputils-ping telnet \
    ssh-client \
    unzip tar gzip
# Problems:
# - 500+ packages with potential vulnerabilities
# - Includes shells for attackers
# - Package manager available for installing malware
# - Networking tools for reconnaissance

# Vulnerable: Using :latest tag
FROM node:latest
# Problem: Unpredictable, may change and break builds
```

**Why**: Minimal images dramatically reduce attack surface. A typical Ubuntu image contains 100+ binaries that can be used for privilege escalation (`sudo`, `su`), lateral movement (`ssh`, `curl`, `wget`), or data exfiltration (`nc`, `tar`). Distroless images contain only the application runtime, reducing CVE count by 80-90%.

**Refs**: CWE-250, CIS Docker Benchmark 4.1, NIST 800-190 Section 3.1

---

## Rule: Non-Root User Directive

**Level**: `strict`

**When**: Creating Dockerfiles

**Do**: Create and switch to a non-root user
```dockerfile
FROM node:20-alpine

# Create non-root user with specific UID for consistency across containers
RUN addgroup -g 10001 -S appgroup && \
    adduser -u 10001 -S -G appgroup -h /app -s /sbin/nologin appuser

WORKDIR /app

# Copy with correct ownership
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci --only=production && npm cache clean --force

COPY --chown=appuser:appgroup . .

# Switch to non-root user
USER appuser:appgroup

EXPOSE 3000
CMD ["node", "server.js"]
```

```dockerfile
# For Python applications
FROM python:3.12-alpine

RUN addgroup -g 10001 -S appgroup && \
    adduser -u 10001 -S -G appgroup -h /app -s /sbin/nologin appuser

WORKDIR /app

COPY --chown=appuser:appgroup requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

COPY --chown=appuser:appgroup . .

USER appuser:appgroup

ENV PATH="/app/.local/bin:$PATH"
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

```dockerfile
# Using numeric UID for scratch/distroless
FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app

FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app /app
# Use numeric UID (nobody = 65534)
USER 65534:65534
ENTRYPOINT ["/app"]
```

**Don't**: Run containers as root
```dockerfile
# Vulnerable: No USER directive (runs as root)
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["node", "server.js"]
# Risk: Container escape = root access on host

# Vulnerable: Explicitly running as root
USER root
RUN npm install
# Never switch back to non-root
CMD ["node", "server.js"]
```

**Why**: Container escape vulnerabilities like CVE-2019-5736 (runc) and CVE-2020-15257 (containerd) allow attackers to break out of containers. If the container runs as root (UID 0), the attacker gains root on the host. Running as non-root limits impact to unprivileged user access, significantly reducing the severity of container escapes.

**Refs**: CWE-250, CWE-269, CIS Docker Benchmark 4.1, NIST 800-190 Section 4.2.1

---

## Rule: Multi-Stage Builds

**Level**: `strict`

**When**: Building application containers

**Do**: Use multi-stage builds to separate build and runtime environments
```dockerfile
# Stage 1: Build environment with all build tools
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git ca-certificates tzdata

WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-s -w -X main.version=${VERSION}" \
    -o /app/server ./cmd/server

# Stage 2: Minimal runtime
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]
```

```dockerfile
# Node.js multi-stage build
FROM node:20-alpine AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --production

# Runtime stage
FROM node:20-alpine AS runtime
RUN apk add --no-cache tini && \
    addgroup -g 10001 -S appgroup && \
    adduser -u 10001 -S appuser -G appgroup

WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /build/dist ./dist
COPY --from=builder --chown=appuser:appgroup /build/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /build/package.json ./

USER appuser:appgroup
EXPOSE 3000
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/server.js"]
```

```dockerfile
# Python multi-stage with virtual environment
FROM python:3.12-alpine AS builder
RUN apk add --no-cache build-base libffi-dev
WORKDIR /build
COPY requirements.txt .
RUN python -m venv /opt/venv && \
    /opt/venv/bin/pip install --no-cache-dir -r requirements.txt

FROM python:3.12-alpine AS runtime
RUN addgroup -g 10001 -S appgroup && \
    adduser -u 10001 -S appuser -G appgroup
COPY --from=builder /opt/venv /opt/venv
COPY --chown=appuser:appgroup . /app
WORKDIR /app
USER appuser:appgroup
ENV PATH="/opt/venv/bin:$PATH"
CMD ["python", "app.py"]
```

**Don't**: Include build tools in runtime images
```dockerfile
# Vulnerable: Build tools in runtime image
FROM node:20
WORKDIR /app
COPY . .
RUN npm install && npm run build
# npm, build tools, dev dependencies all in final image
EXPOSE 3000
CMD ["node", "dist/server.js"]
# Problems:
# - Includes npm (can install malware)
# - Includes dev dependencies (larger attack surface)
# - Source code visible in image
```

**Why**: Build environments contain compilers, package managers, development tools, and source code that aren't needed at runtime and increase attack surface. Attackers can use these tools to download malware, compile exploits, or exfiltrate data. Multi-stage builds produce minimal images with only runtime dependencies.

**Refs**: CIS Docker Benchmark 4.9, NIST 800-190 Section 3.1

---

## Rule: No Secrets in Build Arguments or Layers

**Level**: `strict`

**When**: Handling secrets during container build or runtime

**Do**: Use Docker BuildKit secrets or runtime injection
```dockerfile
# syntax=docker/dockerfile:1.4

FROM python:3.12-alpine AS builder

# Mount secrets during build (not stored in layers)
RUN --mount=type=secret,id=pip_token \
    pip install --no-cache-dir \
    --extra-index-url https://$(cat /run/secrets/pip_token)@pypi.example.com/simple \
    -r requirements.txt

FROM python:3.12-alpine AS runtime
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY . /app
USER nobody:nobody
CMD ["python", "/app/main.py"]
```

```bash
# Build with BuildKit secrets
DOCKER_BUILDKIT=1 docker build \
  --secret id=pip_token,src=./pip_token.txt \
  -t myapp:latest .
```

```dockerfile
# Runtime secret injection via environment (from orchestrator)
FROM python:3.12-alpine
COPY . /app
USER nobody:nobody
# Secrets injected at runtime by Docker/Kubernetes
CMD ["python", "/app/main.py"]
```

```yaml
# docker-compose.yml with secrets
version: '3.8'
services:
  app:
    build: .
    secrets:
      - db_password
      - api_key
    environment:
      - DATABASE_PASSWORD_FILE=/run/secrets/db_password
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  db_password:
    external: true
  api_key:
    external: true
```

**Don't**: Embed secrets in images
```dockerfile
# Vulnerable: Secrets in ARG (visible in history)
ARG DATABASE_PASSWORD
ENV DATABASE_PASSWORD=${DATABASE_PASSWORD}
# docker history shows the value

# Vulnerable: Secrets in ENV
ENV API_KEY=sk-1234567890abcdef
# Plaintext in image configuration

# Vulnerable: Copying secret files
COPY credentials.json /app/
COPY .env /app/
# Secrets extractable from image layers

# Vulnerable: Secrets in RUN commands
RUN curl -H "Authorization: Bearer sk-secret123" https://api.example.com
# Visible in layer history
```

**Why**: Docker image layers are immutable and can be inspected. Secrets in ARG values appear in `docker history`. Secrets in ENV are stored in image config. Secrets in COPY persist in layers even if deleted later. Anyone with image access can extract these secrets. This violates secret management principles and makes rotation impossible.

**Refs**: CWE-798, CWE-522, CIS Docker Benchmark 4.10, NIST 800-190 Section 4.2.3

---

## Rule: Image Vulnerability Scanning

**Level**: `strict`

**When**: Building and deploying Docker images

**Do**: Integrate vulnerability scanning in CI/CD pipelines
```yaml
# GitHub Actions with Trivy
name: Build and Scan
on: [push, pull_request]

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Scan for vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          format: 'table'
          exit-code: '1'
          severity: 'CRITICAL,HIGH'
          ignore-unfixed: true

      - name: Scan for secrets
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          scanners: 'secret'
          exit-code: '1'

      - name: Scan Dockerfile
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          scan-ref: '.'
          exit-code: '1'
          severity: 'CRITICAL,HIGH'
```

```bash
# Local scanning with Trivy
trivy image --severity CRITICAL,HIGH --exit-code 1 myapp:latest

# Scan with vulnerability database update
trivy image --download-db-only
trivy image --skip-db-update myapp:latest

# Scan for secrets and misconfigurations
trivy image --scanners vuln,secret,config myapp:latest

# Generate SBOM
trivy image --format cyclonedx --output sbom.json myapp:latest

# Scan with Grype
grype myapp:latest --fail-on high

# Scan with Docker Scout
docker scout cves myapp:latest --exit-code --only-severity critical,high
```

```dockerfile
# Dockerfile best practices scanner
# hadolint Dockerfile
FROM python:3.12-alpine
# hadolint will flag issues like:
# - Using :latest tag
# - Missing USER directive
# - Curl/wget without verification
```

**Don't**: Deploy without vulnerability scanning
```yaml
# Vulnerable: No security scanning
jobs:
  deploy:
    steps:
      - run: docker build -t myapp:latest .
      - run: docker push myapp:latest
      - run: kubectl set image deployment/app app=myapp:latest
# Risk: Critical CVEs deployed to production
```

**Why**: Container images contain vulnerabilities in base images, system packages, and application dependencies. Average images contain 50-200 vulnerabilities. Without scanning, critical vulnerabilities like remote code execution can be deployed. Automated scanning catches known CVEs before deployment and generates SBOMs for compliance.

**Refs**: CWE-1104, NIST 800-190 Section 3.2, CIS Docker Benchmark 4.4

---

## Rule: Content Trust and Image Signing

**Level**: `warning`

**When**: Distributing or consuming Docker images

**Do**: Sign images and enable content trust
```bash
# Enable Docker Content Trust
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://notary.example.com

# Push will automatically sign
docker push myregistry.io/myapp:v1.0.0

# Pull will verify signature
docker pull myregistry.io/myapp:v1.0.0

# Sign with Cosign (recommended)
cosign generate-key-pair

# Sign image
cosign sign --key cosign.key myregistry.io/myapp:v1.0.0

# Verify signature
cosign verify --key cosign.pub myregistry.io/myapp:v1.0.0

# Keyless signing with OIDC (GitHub Actions)
cosign sign --oidc-issuer=https://token.actions.githubusercontent.com \
  myregistry.io/myapp:v1.0.0
```

```yaml
# GitHub Actions: Keyless signing with Cosign
- name: Sign image with Cosign
  run: |
    cosign sign --yes \
      --oidc-issuer=https://token.actions.githubusercontent.com \
      ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
  env:
    COSIGN_EXPERIMENTAL: "true"
```

**Don't**: Use unsigned images without verification
```bash
# Vulnerable: No signature verification
docker pull someregistry.io/app:latest
docker run someregistry.io/app:latest
# Risk: Image may be tampered or from malicious source

# Vulnerable: Disabled content trust
export DOCKER_CONTENT_TRUST=0
docker pull myregistry.io/myapp:latest
```

**Why**: Without signing, attackers can replace legitimate images through registry compromise, man-in-the-middle attacks, or typosquatting (e.g., `myap` vs `myapp`). Image signing provides cryptographic proof of origin and integrity. Content trust prevents pulling unsigned or tampered images.

**Refs**: CWE-494, CIS Docker Benchmark 4.5, NIST 800-190 Section 3.3

---

## Rule: Read-Only Root Filesystem

**Level**: `warning`

**When**: Running Docker containers

**Do**: Mount root filesystem as read-only with explicit writable directories
```bash
# Run with read-only root filesystem
docker run --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=100m \
  --tmpfs /var/run:rw,noexec,nosuid,size=10m \
  -v app-logs:/var/log/app:rw \
  myapp:latest

# Docker Compose
version: '3.8'
services:
  app:
    image: myapp:latest
    read_only: true
    tmpfs:
      - /tmp:size=100m,mode=1777
      - /var/run:size=10m
    volumes:
      - app-logs:/var/log/app:rw
      - app-data:/app/data:rw
```

```dockerfile
# Prepare application for read-only filesystem
FROM python:3.12-alpine

WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt && \
    mkdir -p /app/tmp /app/logs /app/.cache && \
    chown -R nobody:nobody /app

USER nobody:nobody

# Configure app to use specific writable directories
ENV TMPDIR=/app/tmp
ENV CACHE_DIR=/app/.cache
CMD ["python", "app.py"]
```

**Don't**: Allow unrestricted filesystem writes
```bash
# Vulnerable: Writable filesystem
docker run myapp:latest
# Attacker can:
# - Modify application binaries
# - Install backdoors
# - Write malware
# - Modify configuration files
```

**Why**: A writable root filesystem allows attackers to modify application binaries, install backdoors, write malware, or tamper with configuration. Read-only filesystems prevent persistent modifications and limit the impact of application compromise. tmpfs mounts provide necessary writable space without persistence.

**Refs**: CWE-284, CIS Docker Benchmark 5.12, NIST 800-190 Section 4.2.2

---

## Rule: Drop All Capabilities

**Level**: `strict`

**When**: Running Docker containers

**Do**: Drop all Linux capabilities and add only required ones
```bash
# Drop all capabilities
docker run --cap-drop=ALL \
  --security-opt=no-new-privileges:true \
  myapp:latest

# Add back specific capability if absolutely required
docker run --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --user 1000:1000 \
  --security-opt=no-new-privileges:true \
  myapp:latest
```

```yaml
# Docker Compose
version: '3.8'
services:
  app:
    image: myapp:latest
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    # Only if binding to port < 1024
    # cap_add:
    #   - NET_BIND_SERVICE
```

**Common capabilities and their risks**:
```bash
# Dangerous capabilities to never add:
# CAP_SYS_ADMIN   - Mount filesystems, load kernel modules
# CAP_SYS_PTRACE  - Debug processes, bypass security
# CAP_SYS_RAWIO   - Direct I/O access
# CAP_NET_ADMIN   - Network configuration changes
# CAP_DAC_OVERRIDE - Bypass file permission checks

# Rarely needed capabilities:
# CAP_NET_BIND_SERVICE - Bind to ports < 1024
# CAP_CHOWN           - Change file ownership
# CAP_SETUID          - Change UID (dangerous!)
```

**Don't**: Run with default or elevated capabilities
```bash
# Vulnerable: Default capabilities (13 capabilities)
docker run myapp:latest

# Critical: All capabilities
docker run --cap-add=ALL myapp:latest
# Equivalent to root on host

# Vulnerable: Dangerous capabilities
docker run --cap-add=SYS_ADMIN myapp:latest
docker run --cap-add=SYS_PTRACE myapp:latest
```

**Why**: Linux capabilities divide root privileges into distinct units. Docker containers have 13 capabilities by default, including dangerous ones like CAP_NET_RAW (ARP spoofing, packet sniffing) and CAP_SETFCAP (setting file capabilities). Dropping all capabilities and adding only required ones follows least privilege and significantly reduces attack surface.

**Refs**: CWE-250, CWE-269, CIS Docker Benchmark 5.3-5.4, NIST 800-190 Section 4.2.1

---

## Rule: No Privileged Containers

**Level**: `strict`

**When**: Running Docker containers

**Do**: Run containers with restricted privileges
```bash
# Secure container runtime
docker run \
  --cap-drop=ALL \
  --security-opt=no-new-privileges:true \
  --security-opt=seccomp=default.json \
  --read-only \
  --user 10001:10001 \
  myapp:latest
```

```yaml
# Docker Compose with security options
version: '3.8'
services:
  app:
    image: myapp:latest
    user: "10001:10001"
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
      - seccomp:seccomp-profile.json
    read_only: true
    tmpfs:
      - /tmp
```

**Don't**: Run privileged containers
```bash
# Critical vulnerability: Privileged mode
docker run --privileged myapp:latest
# Gives full host access:
# - All capabilities
# - Access to all devices
# - Can mount host filesystem
# - Can load kernel modules
# - Effectively root on host

# Vulnerable: Elevated privileges
docker run --cap-add=SYS_ADMIN myapp:latest
docker run --device=/dev/sda myapp:latest
docker run -v /:/host myapp:latest
```

**Why**: Privileged containers have full access to the host system, effectively negating container isolation. An attacker who compromises a privileged container has root access to the host and can escape the container trivially. This is the most severe container security misconfiguration.

**Refs**: CWE-250, CWE-269, CIS Docker Benchmark 5.4, NIST 800-190 Section 4.2.1

---

## Rule: Container Health Checks

**Level**: `advisory`

**When**: Creating production Dockerfiles

**Do**: Implement comprehensive health checks
```dockerfile
FROM python:3.12-alpine

WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt

USER nobody:nobody

# Health check with appropriate intervals
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1

EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

```dockerfile
# For containers without wget/curl
FROM gcr.io/distroless/base-debian12:nonroot

COPY --from=builder /app/server /server
COPY --from=builder /app/healthcheck /healthcheck

USER nonroot:nonroot

HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
  CMD ["/healthcheck"]

ENTRYPOINT ["/server"]
```

```dockerfile
# Multiple health check approaches
# HTTP endpoint
HEALTHCHECK CMD curl -f http://localhost:8080/health || exit 1

# TCP port check
HEALTHCHECK CMD nc -z localhost 5432 || exit 1

# Custom script
HEALTHCHECK CMD /app/healthcheck.sh || exit 1

# PostgreSQL
HEALTHCHECK CMD pg_isready -U postgres || exit 1

# Redis
HEALTHCHECK CMD redis-cli ping || exit 1
```

**Don't**: Skip health checks in production
```dockerfile
# Vulnerable: No health check
FROM python:3.12-alpine
COPY . /app
CMD ["python", "/app/main.py"]
# Problems:
# - No automatic restart on failure
# - No readiness detection
# - Harder to detect compromised containers
```

**Why**: Without health checks, containers that crash, deadlock, or become unresponsive continue running. Orchestrators can't automatically restart failed containers or route traffic away from unhealthy instances. Health checks enable automatic recovery and can detect anomalies that may indicate compromise.

**Refs**: CIS Docker Benchmark 4.6, NIST 800-190 Section 4.4.1

---

## Rule: Resource Limits

**Level**: `warning`

**When**: Running Docker containers in production

**Do**: Set memory, CPU, and PID limits
```bash
# Run with resource limits
docker run \
  --memory="512m" \
  --memory-swap="512m" \
  --memory-reservation="256m" \
  --cpus="1.0" \
  --cpu-shares=1024 \
  --pids-limit=100 \
  --ulimit nofile=1024:1024 \
  --ulimit nproc=64:64 \
  myapp:latest
```

```yaml
# Docker Compose resource limits
version: '3.8'
services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
          pids: 100
        reservations:
          cpus: '0.5'
          memory: 256M
    ulimits:
      nofile:
        soft: 1024
        hard: 1024
      nproc:
        soft: 64
        hard: 64
```

```bash
# System-wide Docker daemon defaults
# /etc/docker/daemon.json
{
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 1024,
      "Soft": 1024
    },
    "nproc": {
      "Name": "nproc",
      "Hard": 64,
      "Soft": 64
    }
  }
}
```

**Don't**: Run containers without resource limits
```bash
# Vulnerable: No limits
docker run myapp:latest
# Risks:
# - Fork bombs can exhaust PIDs
# - Memory leaks can OOM host
# - CPU mining can starve other containers
# - File descriptor exhaustion
```

**Why**: Containers without resource limits can consume all host resources, causing denial of service to other containers and the host system. Attackers exploit this through fork bombs (--pids-limit prevents), memory exhaustion (--memory prevents), and CPU abuse (--cpus prevents). Limits ensure fair resource sharing and contain compromise impact.

**Refs**: CWE-400, CWE-770, CIS Docker Benchmark 5.10-5.14, NIST 800-190 Section 4.2.4

---

## Rule: Secure .dockerignore

**Level**: `warning`

**When**: Building Docker images

**Do**: Create comprehensive .dockerignore to exclude sensitive files
```gitignore
# .dockerignore

# Version control
.git
.gitignore
.svn

# Secrets and credentials
.env
.env.*
*.pem
*.key
*.crt
**/secrets/
credentials.json
service-account.json
*.secret

# Build artifacts and dependencies
node_modules
__pycache__
*.pyc
.pytest_cache
.coverage
coverage/
dist/
build/
target/

# IDE and editor files
.vscode
.idea
*.swp
*.swo
*~

# Documentation and tests (usually not needed in runtime)
docs/
*.md
README*
CHANGELOG*
test/
tests/
*_test.go
*.test.js

# Docker files
Dockerfile*
docker-compose*.yml
.dockerignore

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
Jenkinsfile

# OS files
.DS_Store
Thumbs.db

# Log files
*.log
logs/
```

**Don't**: Build images without .dockerignore
```bash
# Vulnerable: No .dockerignore
# The following get copied into the image:
# - .git directory (full history including deleted secrets)
# - .env files with credentials
# - Private keys and certificates
# - IDE settings with personal info
# - Test files and coverage reports
# - node_modules (may differ from npm ci)
```

**Why**: Without .dockerignore, COPY and ADD instructions include all files in the build context, including sensitive data like .git directories (containing full history), environment files with credentials, private keys, and IDE configurations. These become extractable from image layers and may be exposed if the image is published.

**Refs**: CWE-200, CWE-522, CIS Docker Benchmark 4.10

---

## Additional Security Configurations

### Seccomp Profile

```json
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_AARCH64"],
  "syscalls": [
    {
      "names": [
        "read", "write", "open", "close", "stat", "fstat",
        "lstat", "poll", "lseek", "mmap", "mprotect", "munmap",
        "brk", "rt_sigaction", "rt_sigprocmask", "ioctl",
        "access", "pipe", "select", "sched_yield", "mremap",
        "msync", "mincore", "madvise", "shmget", "shmat",
        "exit", "exit_group", "wait4", "kill", "uname",
        "fcntl", "flock", "fsync", "fdatasync", "truncate",
        "ftruncate", "getdents", "getcwd", "chdir", "fchdir",
        "rename", "mkdir", "rmdir", "link", "unlink", "symlink",
        "readlink", "chmod", "fchmod", "chown", "fchown",
        "lchown", "umask", "gettimeofday", "getuid", "getgid",
        "geteuid", "getegid", "getpgid", "getppid", "getpgrp",
        "setsid", "setpgid", "getgroups", "setresuid", "setresgid",
        "getresuid", "getresgid", "sigaltstack", "rt_sigreturn",
        "clock_gettime", "clock_getres", "clock_nanosleep",
        "futex", "sched_getaffinity", "epoll_create", "epoll_ctl",
        "epoll_wait", "epoll_pwait", "epoll_create1", "dup",
        "dup2", "dup3", "socket", "connect", "accept", "accept4",
        "sendto", "recvfrom", "sendmsg", "recvmsg", "bind",
        "listen", "getsockname", "getpeername", "socketpair",
        "setsockopt", "getsockopt", "clone", "execve", "arch_prctl",
        "prctl", "pread64", "pwrite64", "readv", "writev",
        "getrandom", "memfd_create", "openat", "fstatat", "unlinkat",
        "renameat", "faccessat", "fchmodat", "fchownat", "newfstatat"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}
```

### AppArmor Profile

```bash
# /etc/apparmor.d/docker-myapp
#include <tunables/global>

profile docker-myapp flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
  network inet udp,
  network inet icmp,

  deny @{PROC}/* w,
  deny @{PROC}/sys/** w,
  deny /sys/** w,

  /app/** r,
  /app/logs/** rw,
  /tmp/** rw,

  deny /etc/shadow r,
  deny /etc/passwd r,
}
```

### Docker Daemon Security Configuration

```json
{
  "icc": false,
  "userns-remap": "default",
  "no-new-privileges": true,
  "seccomp-profile": "/etc/docker/seccomp-profile.json",
  "live-restore": true,
  "userland-proxy": false,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65535,
      "Soft": 65535
    }
  }
}
```

**Refs**: CIS Docker Benchmark Section 2, NIST 800-190 Section 4

