Skip to main content

Docker Security

Comprehensive security practices, vulnerability scanning, and hardening techniques for Docker containers and images.

Image Security

Secure Base Images

# Use official images from trusted sources
FROM node:18-alpine # ✓ Official Node.js image
FROM alpine:3.18 # ✓ Minimal, frequently updated
FROM distroless/java # ✓ Distroless for production

# Avoid unofficial or outdated images
FROM random/node # ✗ Unofficial source
FROM ubuntu:14.04 # ✗ Outdated version
FROM node:latest # ✗ Unpredictable updates

Image Vulnerability Scanning

# Docker Scout (built-in)
docker scout quickview image_name
docker scout cves image_name
docker scout recommendations image_name

# Trivy scanner
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myapp:latest

# Snyk scanner
docker run --rm -v $(pwd):/project \
snyk/snyk test --docker myapp:latest

# Clair scanner
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
quay.io/coreos/clair:latest

# Anchore scanner
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
anchore/engine-cli anchore-cli image add myapp:latest

Secure Image Building

# Multi-stage builds to reduce attack surface
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine AS runtime
WORKDIR /app
# Copy only necessary files
COPY --from=builder /app/node_modules ./node_modules
COPY . .
# Remove unnecessary files
RUN rm -rf /tmp/* /var/cache/apk/*

# Use specific versions
FROM node:18.17.0-alpine3.18 # ✓ Specific version
FROM node:18-alpine # ✓ Acceptable
FROM node:latest # ✗ Unpredictable

# Update packages during build
RUN apk update && apk upgrade && apk add --no-cache curl
RUN apt-get update && apt-get upgrade -y && apt-get clean

Container Runtime Security

User Management

# Create and use non-root user
FROM alpine:3.18
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
USER appuser

# Alternative approach
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001 -G nodejs
COPY --chown=nextjs:nodejs . /app
USER nextjs

Container Security Options

# Drop all capabilities and add only necessary ones
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx

# Run with read-only filesystem
docker run --read-only --tmpfs /tmp --tmpfs /var/run nginx

# Disable new privileges
docker run --security-opt no-new-privileges nginx

# Set AppArmor profile
docker run --security-opt apparmor:docker-default nginx

# Set SELinux labels
docker run --security-opt label=level:s0:c123,c456 nginx

# Use user namespace remapping
docker run --userns-remap=default nginx

# Limit resources
docker run --memory=512m --cpus=1.0 --pids-limit=100 nginx

Secrets Management

# Use Docker secrets (Swarm mode)
echo "mysecret" | docker secret create db_password -
docker service create --secret db_password myapp

# Use external secret management
docker run -e API_KEY_FILE=/run/secrets/api_key \
-v /path/to/secrets:/run/secrets:ro \
myapp

# Avoid secrets in environment variables
docker run -e DATABASE_URL="postgres://user:password@host/db" myapp # ✗ Bad

# Use secret files instead
docker run -v /secrets/db_creds:/run/secrets/db_creds:ro myapp # ✓ Good

Network Security

Network Isolation

# Create isolated network
docker network create --internal isolated-network

# Disable inter-container communication
docker network create --opt com.docker.network.bridge.enable_icc=false secure-net

# Use custom bridge with specific subnet
docker network create --subnet=172.30.0.0/24 --gateway=172.30.0.1 private-net

# Host network (use carefully)
docker run --network host nginx # Shares host networking stack

Port Security

# Bind to localhost only
docker run -p 127.0.0.1:8080:80 nginx

# Specific interface binding
docker run -p 192.168.1.100:8080:80 nginx

# Avoid binding to all interfaces
docker run -p 8080:80 nginx # ✗ Binds to 0.0.0.0
docker run -p 0.0.0.0:8080:80 nginx # ✗ Explicit all interfaces

# Use random host ports for non-public services
docker run -P nginx # Random host ports

TLS and Encryption

# Enable Docker daemon TLS
dockerd --tlsverify \
--tlscacert=ca.pem \
--tlscert=server-cert.pem \
--tlskey=server-key.pem \
-H=0.0.0.0:2376

# Connect with TLS client
docker --tlsverify \
--tlscacert=ca.pem \
--tlscert=cert.pem \
--tlskey=key.pem \
-H=tcp://docker-host:2376 version

Docker Daemon Security

Daemon Configuration

{
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"seccomp-profile": "/etc/docker/seccomp.json",
"apparmor-profile": "docker-default",
"selinux-enabled": true,
"userns-remap": "default",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}

Access Control

# Create docker group (if not exists)
sudo groupadd docker

# Add user to docker group
sudo usermod -aG docker $USER

# Set proper permissions on docker socket
sudo chmod 660 /var/run/docker.sock
sudo chown root:docker /var/run/docker.sock

# Use rootless Docker
dockerd-rootless-setuptool.sh install
systemctl --user start docker

Audit and Logging

# Enable audit logging
dockerd --log-level=debug

# Configure centralized logging
docker run --log-driver=syslog nginx
docker run --log-driver=fluentd --log-opt fluentd-address=localhost:24224 nginx

# Monitor Docker events
docker events --filter type=container --filter event=start

# Use audit framework
auditctl -w /var/run/docker.sock -p rwxa -k docker
auditctl -w /usr/bin/docker -p rwxa -k docker

Container Hardening

Runtime Security

# Use security profiles
docker run --security-opt seccomp=seccomp-profile.json nginx
docker run --security-opt apparmor=custom-profile nginx

# Limit system calls
docker run --security-opt seccomp=unconfined nginx # ✗ Dangerous
docker run --security-opt seccomp=seccomp-profile.json nginx # ✓ Restricted

# Resource limits
docker run \
--memory=512m \
--memory-swap=512m \
--cpus=1.0 \
--pids-limit=100 \
--ulimit nofile=1024:1024 \
nginx

File System Security

# Use read-only root filesystem
FROM alpine:3.18
RUN mkdir -p /app/tmp /app/logs
VOLUME ["/app/tmp", "/app/logs"]
# Application runs with read-only root filesystem
# Run with read-only filesystem
docker run --read-only \
--tmpfs /tmp \
--tmpfs /var/run \
--tmpfs /var/log \
nginx

Capability Management

# Drop all capabilities
docker run --cap-drop ALL nginx

# Add only required capabilities
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx
docker run --cap-drop ALL --cap-add CHOWN --cap-add DAC_OVERRIDE nginx

# Common capability combinations
# Web server
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx

# Database
docker run --cap-drop ALL --cap-add CHOWN --cap-add DAC_OVERRIDE postgres

# Monitoring tools
docker run --cap-drop ALL --cap-add SYS_PTRACE monitoring-app

Security Scanning and Compliance

Automated Security Scanning

# CI/CD integration with Trivy
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest

# Docker Bench Security
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /usr/lib/systemd:/usr/lib/systemd:ro \
-v /etc:/etc:ro \
--label docker_bench_security \
docker/docker-bench-security

# CIS Docker Benchmark
docker run --rm -it --net host --pid host --cap-add audit_control \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /etc:/etc:ro \
aquasec/docker-bench

Content Trust

# Enable Docker Content Trust
export DOCKER_CONTENT_TRUST=1

# Pull only signed images
docker pull alpine:latest # Will verify signature

# Push signed images
docker push myregistry/myapp:latest # Will sign image

# Disable for specific command
DOCKER_CONTENT_TRUST=0 docker pull untrusted-image

Image Signing

# Generate signing keys
docker trust key generate mykey

# Add signer to repository
docker trust signer add --key mykey.pub mykey myregistry/myapp

# Sign and push image
docker trust sign myregistry/myapp:latest

# Verify image signature
docker trust inspect myregistry/myapp:latest

Security Best Practices

Development Security

# Secure Dockerfile practices
FROM node:18-alpine

# Don't run as root
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001 -G nodejs

# Install security updates
RUN apk update && apk upgrade

# Copy files with correct ownership
COPY --chown=nextjs:nodejs package*.json ./
RUN npm ci --only=production

# Remove unnecessary packages
RUN apk del .build-deps

# Switch to non-root user
USER nextjs

# Use COPY instead of ADD
COPY app.js . # ✓ Secure
ADD app.js . # ✗ Less secure

# Don't store secrets in images
# ENV SECRET_KEY=secret123 # ✗ Bad
# Use runtime secrets instead

Production Security

# docker-compose.yml security configuration
version: '3.8'

services:
web:
image: myapp:latest
read_only: true
tmpfs:
- /tmp
- /var/run
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
- apparmor:docker-default
ulimits:
nofile:
soft: 1024
hard: 1024
mem_limit: 512m
cpus: 1.0
pids_limit: 100

Security Monitoring

# Monitor security events
docker events --filter type=container --filter event=die

# Regular security scans
# Schedule daily scans
0 2 * * * docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image --quiet $(docker images --format "{{.Repository}}:{{.Tag}}")

# Monitor for new vulnerabilities
docker scout watch myapp:latest

Quick Security Checklist

Image Security

  • Use official base images
  • Keep base images updated
  • Scan images for vulnerabilities
  • Use specific image tags
  • Remove unnecessary packages
  • Don't store secrets in images

Runtime Security

  • Run as non-root user
  • Use read-only filesystems
  • Drop unnecessary capabilities
  • Set resource limits
  • Use security profiles
  • Enable content trust

Network Security

  • Use custom networks
  • Avoid host networking
  • Bind ports to specific interfaces
  • Enable network encryption
  • Implement network segmentation

Operational Security

  • Regular security updates
  • Audit container configurations
  • Monitor security events
  • Implement secrets management
  • Use least privilege principle
  • Regular vulnerability assessments

Security Tools Reference

Vulnerability Scanners

  • Trivy - Comprehensive vulnerability scanner
  • Docker Scout - Built-in Docker security scanning
  • Snyk - Developer-first security scanning
  • Anchore - Enterprise container security
  • Clair - Open source vulnerability scanner

Security Frameworks

  • CIS Docker Benchmark - Security configuration guide
  • NIST Container Security - Federal security guidelines
  • Docker Bench Security - Automated security checks

Compliance Tools

  • Open Policy Agent (OPA) - Policy-based control
  • Falco - Runtime security monitoring
  • Gatekeeper - Kubernetes policy controller