TechLead
Lesson 9 of 18
5 min read
Docker & DevOps

Docker Security Best Practices

Secure your Docker containers and images with best practices for production deployments

Why Docker Security Matters

Containers share the host kernel, so a vulnerability in one container can potentially affect the entire host system. Following security best practices is essential for production deployments.

1. Don't Run as Root

# ❌ Running as root (default)
FROM node:20-alpine
WORKDIR /app
COPY . .
CMD ["node", "server.js"]

# ✅ Create and use a non-root user
FROM node:20-alpine

# Create a non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --production

# Switch to non-root user
USER appuser

CMD ["node", "server.js"]

2. Use Minimal Base Images

# ❌ Full image with unnecessary tools
FROM node:20          # ~1 GB, includes build tools

# ✅ Alpine variant
FROM node:20-alpine   # ~130 MB, minimal

# ✅✅ Distroless (even more secure)
FROM gcr.io/distroless/nodejs20  # No shell, no package manager

3. Scan Images for Vulnerabilities

# Scan with Docker Scout
docker scout cves myapp:latest

# Scan with Trivy (popular open-source scanner)
trivy image myapp:latest

# Scan during CI/CD
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest

4. Never Store Secrets in Images

# ❌ NEVER do this
ENV API_KEY=sk-1234567890
COPY .env /app/.env

# ✅ Pass secrets at runtime
# docker run -e API_KEY=sk-xxx myapp

# ✅ Use Docker secrets (Swarm) or mount secret files
# docker run -v ./secrets:/run/secrets:ro myapp

5. Use Read-Only Filesystem

# Run with read-only root filesystem
docker run --read-only \
  --tmpfs /tmp \
  --tmpfs /var/run \
  myapp:latest
# In docker-compose.yml
services:
  api:
    image: myapp:latest
    read_only: true
    tmpfs:
      - /tmp
      - /var/run

6. Limit Container Capabilities

# Drop all capabilities and add only what's needed
docker run \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  myapp:latest

# Prevent privilege escalation
docker run --security-opt=no-new-privileges myapp:latest

7. Set Resource Limits

# docker-compose.yml
services:
  api:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 128M
    restart: unless-stopped

Security Checklist

Production Security Checklist

  • ☐ Use non-root user in containers
  • ☐ Use minimal base images (Alpine or Distroless)
  • ☐ Scan images for vulnerabilities regularly
  • ☐ Never bake secrets into images
  • ☐ Pin image versions (no latest tag)
  • ☐ Use read-only filesystems where possible
  • ☐ Drop unnecessary Linux capabilities
  • ☐ Set resource limits (CPU, memory)
  • ☐ Use multi-stage builds to minimize attack surface
  • ☐ Enable Docker Content Trust for image signing

Continue Learning