← Back to Docker Mastery
Advanced15 min read

Security

Secure Docker deployments — image scanning, runtime security, secrets management, network isolation, and production hardening.

Image Security

Start with minimal, trusted base images from official sources. Scan every image for CVEs before deployment. Pin images by digest, not tag, for reproducible and verified builds.

Remove unnecessary packages and tools from production images — no shell, no package manager, no compiler. Distroless and scratch images minimize attack surface.

  • Sign images with cosign for supply chain verification
  • Enable Docker Content Trust (DCT) for signed pulls
  • Rebuild images regularly to incorporate base image patches
# Scan before deploy
trivy image --severity CRITICAL,HIGH myapp:latest

# Pin by digest
FROM node:20-alpine@sha256:exact-digest-here

Runtime Security

Run containers as non-root users. Add USER node or create a dedicated user in your Dockerfile. Use --read-only to mount the root filesystem as read-only with tmpfs for writable directories.

Drop capabilities with --cap-drop=ALL and add only what is needed. Never run containers with --privileged unless absolutely required.

FROM node:20-alpine
RUN addgroup -S app && adduser -S app -G app
USER app
WORKDIR /app
COPY --chown=app:app . .
CMD ["node", "server.js"]

# Run read-only
docker run --read-only --tmpfs /tmp myapp

Secrets Management

Never embed secrets in images or environment variables in compose files committed to git. Use Docker secrets (Swarm mode), external secret managers (Vault, AWS Secrets Manager), or runtime injection.

Mount secrets as files, not environment variables — environment variables appear in docker inspect output and process listings.

# Docker Swarm secrets
echo "db-password" | docker secret create db_password -
docker service create --secret db_password myapp

# Runtime injection (preferred for Compose)
docker run -e DATABASE_URL \
  -e DATABASE_URL=$(vault kv get -field=url secret/db) myapp

Network Security

Segment networks by function — frontend, backend, and database tiers on separate networks. Use internal: true to prevent external access to backend networks.

Implement least-privilege networking: only expose ports that need external access. Use a reverse proxy as the single entry point with TLS termination.

networks:
  frontend:
  backend:
    internal: true
  database:
    internal: true

services:
  web:
    networks: [frontend, backend]
  api:
    networks: [backend, database]
  db:
    networks: [database]

Security Scanning in CI

Integrate image scanning into your CI pipeline. Fail builds on critical CVEs. Use Hadolint to lint Dockerfiles for security anti-patterns. Audit running containers with Docker Bench for Security.

Establish a vulnerability response process: scan daily, patch within SLA, and maintain an SBOM (Software Bill of Materials) for compliance.

# Hadolint Dockerfile linter
hadolint Dockerfile

# Docker Bench Security
docker run --rm --net host --pid host \
  -v /var/run/docker.sock:/var/run/docker.sock \
  docker/docker-bench-security

Get In Touch


Ready to discuss your next project? Drop me a message.