Tutorial
Docker Security: Best Practices and Hardening
Secure your Docker containers and images. Learn about security scanning, secrets management, and compliance.
TechDevDex Team
12/11/2024
18 min
#Docker#Security#Best Practices#Hardening
Docker Security: Best Practices and Hardening
Docker security is crucial for production environments. This comprehensive guide covers security best practices, vulnerability scanning, and hardening techniques.
Docker Security Fundamentals
Security Layers
- Host Security: Secure the underlying host system
- Docker Daemon Security: Configure Docker daemon securely
- Container Security: Secure container runtime
- Image Security: Use secure base images
- Network Security: Implement proper network policies
Image Security Best Practices
Use Minimal Base Images
# Good: Use minimal base images
FROM alpine:3.18
# Bad: Avoid full OS images
FROM ubuntu:20.04
Scan Images for Vulnerabilities
# Use Docker Scout
docker scout cves myapp:latest
# Use Trivy
trivy image myapp:latest
# Use Snyk
snyk container test myapp:latest
Use Multi-stage Builds
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]
Container Security
Run as Non-Root User
FROM node:18-alpine
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Switch to non-root user
USER nextjs
# Your application code
COPY --chown=nextjs:nodejs . .
Read-Only Filesystem
FROM alpine:3.18
COPY app /app
USER 1001
# Run with read-only filesystem
CMD ["/app"]
# Run container with read-only filesystem
docker run --read-only myapp:latest
Resource Limits
version: '3.8'
services:
web:
image: myapp:latest
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
Secrets Management
Docker Secrets
version: '3.8'
services:
web:
image: myapp:latest
secrets:
- db_password
- api_key
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true
Environment Variables
# Use environment files
docker run --env-file .env myapp:latest
# Pass secrets as environment variables
docker run -e DB_PASSWORD=secret myapp:latest
Network Security
Custom Networks
# Create custom network
docker network create --driver bridge my-network
# Run container on custom network
docker run --network my-network myapp:latest
Network Policies
version: '3.8'
services:
web:
image: nginx:alpine
networks:
- frontend
api:
image: myapp:latest
networks:
- frontend
- backend
database:
image: postgres:13
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
Docker Daemon Security
Configure TLS
# Generate CA certificate
openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# Generate server certificate
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=docker-server" -sha256 -new -key server-key.pem -out server.csr
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -out server-cert.pem
# Configure Docker daemon
dockerd \
--tlsverify \
--tlscacert=ca.pem \
--tlscert=server-cert.pem \
--tlskey=server-key.pem \
-H=0.0.0.0:2376
User Namespace
# Enable user namespace
echo '{"userns-remap": "default"}' > /etc/docker/daemon.json
systemctl restart docker
Security Scanning
Automated Scanning
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build image
run: docker build -t myapp:latest .
- name: Run Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:latest'
format: 'sarif'
output: 'trivy-results.sarif'
Continuous Monitoring
# Set up continuous scanning
docker scout cves myapp:latest --only-severity=high,critical
# Monitor for new vulnerabilities
docker scout watch myapp:latest
Compliance and Auditing
Audit Logging
# Enable audit logging
dockerd --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3
Compliance Scanning
# Use Docker Bench Security
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /etc:/etc:ro \
-v /usr/bin/containerd:/usr/bin/containerd:ro \
-v /usr/bin/runc:/usr/bin/runc:ro \
-v /usr/lib/systemd:/usr/lib/systemd:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--label docker_bench_security \
docker/docker-bench-security
Production Security Checklist
Pre-deployment
- Scan images for vulnerabilities
- Use minimal base images
- Run as non-root user
- Implement resource limits
- Use read-only filesystem
- Configure proper networking
Runtime Security
- Monitor container behavior
- Implement logging
- Set up alerting
- Regular security updates
- Access control
- Network segmentation
Post-deployment
- Regular vulnerability scans
- Security monitoring
- Incident response plan
- Backup and recovery
- Compliance auditing
Conclusion
Docker security requires a multi-layered approach. By following these best practices and implementing proper security measures, you can significantly reduce the attack surface and protect your containerized applications.
Remember to:
- Scan images regularly
- Use minimal base images
- Run containers as non-root
- Implement proper networking
- Monitor and audit continuously
- Stay updated with security patches
Stay secure! 🔒