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
latesttag) - ☐ 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