Skip to main content
Security

Docker Security: Distroless to Runtime

Harden your container supply chain with multi-stage builds, image scanning, runtime policies, and zero-trust networking.

SM
Sara Moussaoui
Security Engineer
11 pages.blog.minRead read
Feb 20, 2025
DockerSecurity

The Container Supply Chain

Container security starts at the base image. Using ubuntu:latest or node:18 pulls thousands of packages you don't need — and each package is an attack surface. Distroless images from Google contain only your application and its runtime dependencies.

Multi-stage builds are your first line of defense. Build in a full-featured image, then copy only the binary and required files to a minimal runtime image.

Docker container security layers infographicDocker container security layers infographic
Container Security — Layered Defense Model
Container Image Size Comparison
ubuntu:22.0477 MB
node:18998 MB
node:18-alpine175 MB
gcr.io/distroless/nodejs18118 MB
scratch (Go binary)12 MB

Image Scanning and Policies

Integrate Trivy or Grype into your CI pipeline to scan images for CVEs on every build. Set a policy: block deployments with Critical or High CVEs, and track Medium CVEs with a remediation SLA.

Pin base image digests (not tags) in production Dockerfiles. Tags are mutable — node:18-alpine might point to a different image tomorrow. Use node:18-alpine@sha256:abc123... for reproducibility.

CVE Severity Policy Matrix
SeverityActionSLAGate
CriticalBlock deployImmediate🚫 Pipeline blocked
HighBlock deploy24 hours🚫 Pipeline blocked
MediumTrack ticket7 days⚠️ Warning only
LowBacklog30 days✅ Pass

Runtime Security

Run containers as non-root with USER 1000:1000. Drop all capabilities with --cap-drop=ALL and add back only what's needed. Mount the filesystem read-only with readOnlyRootFilesystem: true.

In Kubernetes, use Pod Security Standards (restricted profile) to enforce these policies cluster-wide. Combine with Falco for runtime anomaly detection.

DockerfileDockerfile
# Multi-stage distroless build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build

FROM gcr.io/distroless/nodejs18-debian12
COPY --from=builder /app/dist /app
COPY --from=builder /app/node_modules /app/node_modules
USER 1000:1000
CMD ["/app/server.js"]
pages.blog.shareArticle:

pages.blog.ctaTitle

pages.blog.ctaDesc

pages.blog.ctaBtn
SOC2 15-Min SLA 99.99% Uptime