Docker Security¶
🔒 Learning Objectives
- Secure Docker images and containers
- Implement security best practices
- Scan images for vulnerabilities
- Manage secrets securely
Secure your Docker containers and deployments.
Security is Critical
Docker security is often overlooked but essential. Run containers as non-root, scan images regularly, use minimal base images, and never commit secrets. A single vulnerability can compromise your entire system.
Security Checklist
- Use official images from trusted sources
- Run containers as non-root users
- Set resource limits
- Scan images with Trivy or Snyk
- Keep images updated
- Use secrets management, never hardcode credentials
Security Fundamentals¶
Principle of Least Privilege¶
- Run containers as non-root users
- Limit container capabilities
- Use read-only filesystems where possible
- Minimize attack surface
Image Security¶
Use Official Images¶
# Prefer official images
FROM node:16-alpine
# Avoid untrusted sources
# FROM someuser/random-image:latest # ❌
Scan Images¶
# Using Trivy
trivy image nginx:alpine
# Using Docker Scout
docker scout quickview nginx:alpine
# Using Snyk
snyk test --docker nginx:alpine
Keep Images Updated¶
# Check for updates
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.CreatedAt}}"
# Use specific tags, not 'latest'
FROM node:16.20.0-alpine # ✅
FROM node:latest # ❌
Container Security¶
Non-Root User¶
# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
# Use the user
USER appuser
# Or in one line
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser
USER appuser
Read-Only Root Filesystem¶
# Run with read-only root
docker run --read-only alpine
# Allow specific writable directories
docker run --read-only \
--tmpfs /tmp \
--tmpfs /var/run \
alpine
Limit Capabilities¶
# Drop all capabilities, add only needed
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
# Common capabilities to drop
docker run --cap-drop=CHOWN --cap-drop=SETUID --cap-drop=SETGID app
Resource Limits¶
# docker-compose.yml
services:
app:
image: myapp
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
Network Security¶
Network Isolation¶
# Create isolated network
docker network create --internal isolated_network
# Containers can't access external network
docker run --network isolated_network alpine
Firewall Rules¶
# Use iptables to restrict access
iptables -A DOCKER -s 192.168.1.0/24 -j ACCEPT
iptables -A DOCKER -j DROP
Secrets Management¶
Docker Secrets (Swarm)¶
# Create secret
echo "mysecret" | docker secret create db_password -
# Use in service
docker service create \
--secret db_password \
--name app \
myapp
Environment Variables¶
# docker-compose.yml
services:
app:
image: myapp
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Warning
Never commit secrets to version control. Use secret management tools.
Security Scanning¶
Image Vulnerability Scanning¶
# Install Trivy
brew install trivy # macOS
# or
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# Scan image
trivy image nginx:alpine
# Scan with exit code
trivy image --exit-code 1 --severity HIGH,CRITICAL nginx:alpine
CI/CD Integration¶
# .github/workflows/security.yml
name: Security Scan
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build -t myapp .
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp
format: 'sarif'
output: 'trivy-results.sarif'
Best Practices¶
Dockerfile Security¶
# ✅ Good practices
FROM node:16-alpine
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser
WORKDIR /app
COPY --chown=appuser:appuser package*.json ./
RUN npm ci --only=production
COPY --chown=appuser:appuser . .
USER appuser
HEALTHCHECK --interval=30s CMD node healthcheck.js
CMD ["node", "server.js"]
Runtime Security¶
# Security checklist
docker run \
--read-only \
--tmpfs /tmp \
--user 1000:1000 \
--cap-drop=ALL \
--security-opt no-new-privileges:true \
--memory=512m \
--cpus=1.0 \
myapp
Security Tools¶
Docker Bench Security¶
# Run security audit
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
Falco (Runtime Security)¶
# Install Falco
docker run -d \
--name falco \
--privileged \
-v /var/run/docker.sock:/host/var/run/docker.sock:ro \
-v /dev:/host/dev:ro \
-v /proc:/host/proc:ro \
-v /boot:/host/boot:ro \
-v /lib/modules:/host/lib/modules:ro \
-v /usr:/host/usr:ro \
falcosecurity/falco
Exercises¶
- Create a secure Dockerfile with non-root user
- Scan an image for vulnerabilities
- Configure resource limits for a container
- Set up secrets management for a compose file
Previous: Docker Compose | Next: Performance Optimization