Skip to content

Containers have revolutionized application deployment, but they introduce unique security challenges. This guide covers essential Docker security practices for production environments.

Image Security

Use Minimal Base Images

1
2
3
4
5
6
7
8
# ❌ Avoid
FROM ubuntu:latest

# ✅ Better
FROM alpine:3.18

# ✅ Best - distroless
FROM gcr.io/distroless/static-debian11

Scan for Vulnerabilities

1
2
3
4
5
6
7
8
# Trivy
trivy image myapp:latest

# Docker Scout
docker scout cves myapp:latest

# Snyk
snyk container test myapp:latest

Sign and Verify Images

1
2
3
4
5
6
7
# Docker Content Trust
export DOCKER_CONTENT_TRUST=1
docker push myregistry.com/myapp:v1.0

# Cosign
cosign sign --key cosign.key myapp:latest
cosign verify --key cosign.pub myapp:latest

Dockerfile Security

Multi-Stage Builds

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Build stage
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o app

# Runtime stage
FROM gcr.io/distroless/base
COPY --from=builder /app/app /
USER nonroot:nonroot
CMD ["/app"]

Run as Non-Root

1
2
3
4
5
6
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs
COPY --chown=nodejs:nodejs . .
CMD ["node", "server.js"]

Minimize Layers and Secrets

1
2
3
4
5
6
7
# ❌ Bad - secrets in layer
RUN echo "token=secret123" > /config

# ✅ Good - use BuildKit secrets
RUN --mount=type=secret,id=token \
    TOKEN=$(cat /run/secrets/token) && \
    configure-app --token=$TOKEN

Runtime Security

Resource Limits

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# docker-compose.yml
services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          memory: 256M

Read-Only Filesystem

1
2
3
4
docker run --read-only \
  --tmpfs /tmp \
  --tmpfs /var/run \
  myapp:latest

Security Options

1
2
3
4
5
docker run \
  --security-opt=no-new-privileges:true \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  myapp:latest

Network Security

Isolate Networks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true

services:
  web:
    networks:
      - frontend
  db:
    networks:
      - backend

Use TLS

1
2
3
4
5
6
# Enable Docker TLS
dockerd \
  --tlsverify \
  --tlscacert=ca.pem \
  --tlscert=server-cert.pem \
  --tlskey=server-key.pem

Secrets Management

Docker Secrets

1
2
3
4
5
6
echo "db_password" | docker secret create db_pass -

docker service create \
  --name myapp \
  --secret db_pass \
  myapp:latest

External Secret Managers

1
2
3
4
5
6
7
8
# Using Vault
services:
  app:
    environment:
      VAULT_ADDR: http://vault:8200
    command: |
      vault kv get -field=password secret/db > /tmp/pass
      app --db-pass=$(cat /tmp/pass)      

Monitoring and Logging

Container Logs

1
2
3
4
5
# Centralized logging
docker run \
  --log-driver=syslog \
  --log-opt syslog-address=tcp://logserver:514 \
  myapp:latest

Security Monitoring

1
2
3
4
5
6
7
8
# Falco rules for Docker
- rule: Unauthorized Process in Container
  condition: >
    spawned_process and
    container and
    not proc.name in (allowed_processes)    
  output: Unauthorized process in container
  priority: WARNING

Best Practices Checklist

  • Use minimal base images
  • Scan images regularly
  • Sign and verify images
  • Run as non-root user
  • Use read-only filesystems
  • Set resource limits
  • Drop unnecessary capabilities
  • Isolate networks
  • Encrypt data in transit
  • Manage secrets securely
  • Enable audit logging
  • Keep images updated
  • Use specific tags (not latest)
  • Implement health checks
  • Regular security audits

Compliance

CIS Docker Benchmark

1
2
3
4
# Run Docker Bench Security
git clone https://github.com/docker/docker-bench-security.git
cd docker-bench-security
./docker-bench-security.sh

Policy Enforcement

1
2
3
4
5
6
7
# OPA policy for containers
package container.security

deny[msg] {
    input.User == "root"
    msg = "Container must not run as root"
}

Conclusion

Container security requires attention at every stage from image building to runtime. Implement these practices to run Docker securely in production.