Docker foundations
Core Principles of Container Hardening
Section titled “Core Principles of Container Hardening”- Multi-Stage Builds: Build artifacts in a fully-equipped builder stage; copy only the compiled binaries and production dependencies into a clean final image.
- Non-Root Execution: Explicitly define and drop to an unprivileged user (
USER nodeorUSER nonroot). - Minimal Base Images: Prefer Alpine, Debian-slim, or Google Distroless images over full Ubuntu or Debian images.
- Read-Only Root Filesystem: Configure runtime mounts as read-only whenever possible, writing temporary data only to ephemeral
tmpfsmounts. - Deterministic Pinning: Pin base image digests or explicit patch versions to avoid unexpected upstream drift.
Standard Multi-Stage Dockerfile Pattern (Node.js Example)
Section titled “Standard Multi-Stage Dockerfile Pattern (Node.js Example)”Here is a hardened, production-ready multi-stage Dockerfile:
# ----------------------------------------------------# Stage 1: Dependency resolution and compilation# ----------------------------------------------------FROM node:22-alpine AS builder
WORKDIR /app
# Copy dependency manifests first for layer cachingCOPY package.json package-lock.json ./RUN npm ci --ignore-scripts
# Copy source code and compileCOPY . .RUN npm run build && npm prune --production
# ----------------------------------------------------# Stage 2: Minimal runtime image# ----------------------------------------------------FROM node:22-alpine AS runner
WORKDIR /appENV NODE_ENV=productionENV PORT=3000
# Install dumb-init to properly forward Unix signals and reap zombiesRUN apk add --no-cache dumb-init
# Use pre-existing unprivileged node userUSER node
# Copy built application and production dependencies from builder stageCOPY --chown=node:node --from=builder /app/package.json ./COPY --chown=node:node --from=builder /app/node_modules ./node_modulesCOPY --chown=node:node --from=builder /app/dist ./dist
EXPOSE 3000
ENTRYPOINT ["/usr/bin/dumb-init", "--"]CMD ["node", "dist/server/entry.mjs"]Security Configurations in Docker Compose
Section titled “Security Configurations in Docker Compose”When running services locally or on standalone Docker engines, enforce security bounds in docker-compose.yml:
services: web: image: example-app:1.0.0 restart: unless-stopped read_only: true tmpfs: - /tmp:rw,noexec,nosuid,size=64m security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - NET_BIND_SERVICE deploy: resources: limits: cpus: '1.0' memory: 512MAutomated Container Vulnerability Scanning
Section titled “Automated Container Vulnerability Scanning”Integrate Trivy or Docker Scout into your CI pipeline to catch CVEs prior to image registry pushes:
# Scan Docker image locally with Trivytrivy image --severity HIGH,CRITICAL example-app:1.0.0