Docker Security Model
Docker Security Model
Isolation Layers
Docker provides multiple isolation layers:
┌────────────────────────────┐
│ Application │
├────────────────────────────┤
│ Container Runtime │
│ ┌──────────────────────┐ │
│ │ Namespaces │ │ Process, network, mount isolation
│ │ cgroups │ │ Resource limits
│ │ seccomp │ │ System call filtering
│ │ AppArmor/SELinux │ │ Mandatory access control
│ │ capabilities │ │ Privilege dropping
│ └──────────────────────┘ │
├────────────────────────────┤
│ Linux Kernel │
└────────────────────────────┘
Namespaces (Isolation)
| Namespace | Isolates |
|---|---|
| PID | Process IDs |
| NET | Network interfaces, IPs, routing tables |
| MNT | Filesystem mount points |
| UTS | Hostname and domain name |
| IPC | Inter-process communication |
| USER | User and group IDs |
Attack Surface
The primary attack surfaces are:
- Container escape: Breaking out of namespace isolation to access the host
- Docker daemon: If compromised, full host access
- Image supply chain: Malicious base images or dependencies
- Resource exhaustion: A container consuming all host resources
- Network exposure: Unintended port exposure
Container vs VM Security
# Container: shares kernel with host
# A kernel vulnerability affects ALL containers
# VM: separate kernel per VM
# VM escape + kernel exploit needed
Containers are NOT as secure as VMs for multi-tenant isolation. Use VMs or gVisor/Kata Containers for strong isolation.
Security Checklist
- Run containers as non-root
- Use minimal base images
- Scan images for vulnerabilities
- Limit container resources
- Use read-only filesystems where possible
- Drop unnecessary Linux capabilities
- Use Docker Bench Security for auditing
Container Hardening
Container Hardening
Run as Non-Root
# Create non-root user
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
# Switch to non-root before CMD
USER appuser
CMD ["node", "server.js"]
# Verify container runs as non-root
docker exec web id
# uid=1001(appuser) gid=1001(appgroup)
# Check in Dockerfile
docker inspect --format '{{.Config.User}}' myapp
Drop Linux Capabilities
# Drop all capabilities and add only needed ones
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx
# Or in docker-compose.yml
services:
web:
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Bind to ports < 1024
Common capabilities:
| Capability | Allows |
|---|---|
| NET_BIND_SERVICE | Bind to ports < 1024 |
| CHOWN | Change file ownership |
| SETUID/SETGID | Set user/group IDs |
| SYS_PTRACE | Trace processes (debugging) |
Read-Only Root Filesystem
docker run --read-only --tmpfs /tmp --tmpfs /var/run myapp
# Or in docker-compose.yml
services:
web:
read_only: true
tmpfs:
- /tmp
- /var/run
Seccomp Profiles
Seccomp (Secure Computing) filters system calls:
# Use default seccomp profile (applied automatically)
docker run --security-opt seccomp=default myapp
# Use custom seccomp profile
docker run --security-opt seccomp=profile.json myapp
# Disable seccomp (NOT recommended)
docker run --security-opt seccomp=unconfined myapp
AppArmor / SELinux
# AppArmor (Ubuntu/Debian)
docker run --security-opt apparmor=my-profile myapp
# SELinux (RHEL/Fedora)
docker run --security-opt label=type:svirt_apache_t myapp
Docker Daemon Security
// /etc/docker/daemon.json
{
"icc": false, // Disable inter-container communication
"userns-remap": "default", // User namespace remapping
"no-new-privileges": true, // Prevent privilege escalation
"live-restore": true, // Containers survive daemon restart
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Docker Bench Security
Docker Bench Security
What is Docker Bench?
Docker Bench for Security is a script that checks for dozens of common best practices around deploying Docker containers. It implements the CIS Docker Benchmark.
Run Docker Bench
# Run as container (recommended)
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 \
docker/docker-bench-security
# Output shows PASS, WARN, or INFO for each check
Key Checks
Host Configuration:
- [PASS] Ensure a separate partition for containers
- [WARN] Ensure only trusted users are allowed to control Docker
- [PASS] Ensure auditing is configured
Docker Daemon:
- [PASS] Ensure TLS is used for Docker daemon
- [PASS] Ensure default ulimit is configured
- [WARN] Ensure experimental features are not enabled
Container Images:
- [WARN] Ensure a user for the container has been created
- [PASS] Ensure content trust for Docker is enabled
- [WARN] Ensure minimal base image is used
Container Runtime:
- [WARN] Ensure privileged containers are not used
- [PASS] Ensure ports are not mapped to privileged ports
- [WARN] Ensure memory limit is set
Automated Compliance
# CI/CD integration
docker run --rm docker/docker-bench-security 2>&1 | \
grep -E "\[WARN\]|\[FAIL\]" | tee security-report.txt
# Fail build on warnings
docker run --rm docker/docker-bench-security 2>&1 | \
grep -c "\[WARN\]" | xargs -I {} test {} -eq 0
Common Fixes
# Fix: Run as non-root
docker run --user 1000:1000 myapp
# Fix: Drop all capabilities
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
# Fix: Read-only filesystem
docker run --read-only --tmpfs /tmp myapp
# Fix: Set resource limits
docker run --memory 512m --cpus 1.0 myapp
# Fix: No new privileges
docker run --security-opt no-new-privileges:true myapp