devopsApache-2.0 License Verified

Docker Container Hardening

Multi-stage Docker builds, non-root user execution, minimal distroless/Alpine base images, and vulnerability layer minimization.

#Docker#Containers#Security#Alpine#Distroless#Multi-Stage
Install for:
npx domoskills add docker-container-hardening
GitHub
Security verified • Score: 90/100
Installs into: .agent/skills/docker-container-hardening
SKILL.md Prompt Instructions
Read by AI agent on demand
---
name: docker-container-hardening
description: Docker image security, multi-stage builds, non-root users, read-only filesystems, resource limits, and supply chain verification.
license: MIT
version: 1.8.0
---

# Docker Container Hardening

## Overview
A default Docker container runs as root, uses a mutable filesystem, and has no resource bounds. Container hardening removes these attack surfaces and limits blast radius if a container is compromised.

## 1. Multi-Stage Builds — Minimal Final Image
```dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --frozen-lockfile
COPY . .
RUN npm run build

# Stage 2: Runtime — only what is needed
FROM node:20-alpine AS runner
WORKDIR /app

RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public

USER nextjs
EXPOSE 3000
ENV NODE_ENV=production PORT=3000 HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
```

## 2. Non-Root User (Required)
```dockerfile
RUN groupadd -r appgroup && useradd -r -g appgroup -u 1001 appuser
USER appuser
```
Verify: docker run --rm your-image id — must NOT print uid=0(root).

## 3. Read-Only Root Filesystem
```yaml
services:
  app:
    image: myapp:latest
    read_only: true
    tmpfs:
      - /tmp:uid=1001,gid=1001,size=100m
      - /run:uid=1001,gid=1001
```

## 4. Drop Linux Capabilities
```yaml
services:
  app:
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # Only if binding to ports < 1024
```

## 5. Resource Limits (Required)
```yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: "1.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 128M
```
Without limits, a single runaway container can starve the host.

## 6. Image Scanning in CI
```yaml
- name: Scan image
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: myapp:latest
    format: table
    exit-code: 1
    severity: HIGH,CRITICAL
    ignore-unfixed: true
```

## 7. Image Signing (Supply Chain)
```sh
# Cosign keyless signing with GitHub OIDC
cosign sign --yes ghcr.io/myorg/myapp:latest

# Verify
cosign verify ghcr.io/myorg/myapp:latest \
  --certificate-identity=https://github.com/myorg/myapp/.github/workflows/build.yml@refs/heads/main \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com
```

## 8. .dockerignore
```
.git
.env
.env.local
node_modules
dist
*.log
tests/
.github/
```

## 9. Anti-Patterns
- FROM ubuntu:latest — pinless tags break reproducibility; use ubuntu:22.04@sha256:...
- RUN apt-get install without --no-install-recommends — bloats image.
- Storing secrets in Dockerfile ENV or ARG — visible in image history via docker history.
- --privileged containers — grants ALL Linux capabilities, equivalent to root on the host.
- Mounting /var/run/docker.sock — allows container escape.

Ecosystem Radar & Recommended Companions

Dynamic Capability Matrix
Standard Connectors
Antigravity (.agent)Claude Code (.claude)Cursor (.cursor)
Docker Container HardeningActive Capability