Hacktricks-skills docker-security-hardening
Use this skill whenever you need to secure Docker containers, audit Docker configurations, scan for vulnerabilities, or harden Docker deployments. Trigger this for any Docker security questions, container hardening, vulnerability scanning, reviewing Dockerfiles for security issues, or when you need to understand Docker security features like namespaces, capabilities, seccomp, or AppArmor.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/linux-hardening/privilege-escalation/docker-security/docker-security/SKILL.MDDocker Security Hardening
A comprehensive guide to securing Docker containers and deployments.
Quick Start
Immediate Security Checklist
When deploying any container, apply these security measures:
# Essential security flags docker run \ --read-only \ --security-opt=no-new-privileges:true \ --cap-drop=all \ --cap-add=NET_BIND_SERVICE \ --user 1000:1000 \ --memory=512m \ --cpus=1 \ --pids-limit=100 \ --name secure-container \ your-image
Security Features Reference
| Feature | Purpose | Default | Recommended |
|---|---|---|---|
| Prevents filesystem writes | Disabled | Enable |
| Blocks privilege escalation | Disabled | Enable |
| Drops all Linux capabilities | Partial drop | Drop all, add only needed |
| Run as non-root | Root | Non-root user |
| Memory limit | Unlimited | Set appropriate limit |
| CPU limit | Unlimited | Set appropriate limit |
| Process limit | Unlimited | Set to prevent fork bombs |
Container Security Features
Namespaces
Docker uses Linux namespaces for isolation:
- PID namespace: Process isolation
- Mount namespace: Filesystem isolation
- Network namespace: Network stack isolation
- IPC namespace: Inter-process communication isolation
- UTS namespace: Hostname isolation
Security implication: Namespaces provide isolation but are not foolproof. Combined with other mechanisms, they form a defense-in-depth strategy.
Capabilities
Capabilities provide fine-grained privilege control. When a container starts, Docker drops sensitive capabilities by default.
Remaining capabilities by default:
cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Best practice: Drop all capabilities and add only what's needed:
--cap-drop=all --cap-add=NET_BIND_SERVICE --cap-add=CHOWN
Seccomp
Seccomp (Secure Computing Mode) restricts syscalls available to containers.
- Default: Docker uses a default seccomp profile
- Location:
profiles/seccomp/default.json - Disable (not recommended):
--security-opt seccomp=unconfined - Custom profile:
--security-opt seccomp=/path/to/profile.json
AppArmor
AppArmor confines containers to limited resources with per-program profiles.
- Default: Docker has a built-in AppArmor template
- Disable (not recommended):
--security-opt apparmor=unconfined - Custom profile:
--security-opt apparmor=custom-profile-name
SELinux
SELinux provides mandatory access control through labeling:
- Container processes: Labeled as
container_t - Container files: Labeled as
container_file_t - Policy:
can only interact withcontainer_tcontainer_file_t - Disable (not recommended):
--security-opt label:disable
Vulnerability Scanning
Built-in Docker Scan
docker scan <image-name>
Trivy (Recommended)
# Scan image trivy image <image-name>:<tag> # JSON output for CI/CD trivy image --format json --output results.json <image-name>:<tag> # Scan with severity threshold trivy image --severity HIGH,CRITICAL <image-name>:<tag>
Snyk
snyk container test <image> --json-file-output=results.json --severity-threshold=high
Clair Scanner
clair-scanner -w config.yaml --ip YOUR_LOCAL_IP <image-name>:<tag>
Secret Management
❌ Don't Do This
# Bad: Secrets in environment variables ENV API_KEY=secret123 # Bad: Secrets in image layers RUN echo "password123" > /app/config.txt
✅ Do This Instead
Option 1: Docker Secrets (Swarm)
version: "3.7" services: my_service: image: myapp:latest secrets: - my_secret secrets: my_secret: file: ./my_secret_file.txt
Option 2: BuildKit Build-time Secrets
export DOCKER_BUILDKIT=1 docker build --secret id=my_key,src=./secret.txt .
Dockerfile with BuildKit secrets:
FROM node:18 RUN --mount=type=secret,id=my_key \ cp /run/secrets/my_key /app/config/key.txt
Option 3: Runtime Volume Mount
docker run -v /path/to/secrets:/run/secrets:ro myapp
Dockerfile Security Best Practices
Secure Dockerfile Template
# Use specific version, not 'latest' FROM node:18-alpine AS builder # Don't run as root USER node # Install only production dependencies COPY package*.json ./ RUN npm ci --only=production # Copy application code COPY --chown=node:node . . # Use COPY instead of ADD (ADD can fetch URLs and extract archives) # COPY is safer and more predictable # Multi-stage builds reduce attack surface FROM node:18-alpine WORKDIR /app COPY --from=builder --chown=node:node /app . # Non-root user USER node # Health check HEALTHCHECK --interval=30s --timeout=3s \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 EXPOSE 3000 CMD ["node", "server.js"]
Security Anti-Patterns to Avoid
| Anti-Pattern | Risk | Fix |
|---|---|---|
| Unpredictable builds | Pin specific version |
| Full container compromise | Use non-root user |
| Supply chain attack | Use COPY |
| Secrets in image | Use secrets management |
| Host escape | Remove flag |
| No resource limits | DoS attacks | Set memory/CPU limits |
| No health check | Zombie containers | Add HEALTHCHECK |
Hardening Checklist
Pre-Deployment
- Scan image for vulnerabilities
- Use minimal base image (alpine, distroless)
- Remove unnecessary packages
- Set non-root user
- Drop all capabilities, add only needed
- Enable read-only filesystem
- Set resource limits (memory, CPU, pids)
- Enable no-new-privileges
- Configure seccomp/AppArmor/SELinux
- Remove secrets from image
- Add health checks
- Sign images (Docker Content Trust)
Runtime
- Don't mount Docker socket inside containers
- Don't use --privileged flag
- Monitor container behavior
- Keep base images updated
- Use network policies
- Implement secret rotation
- Enable audit logging
Infrastructure
- Use HTTPS for Docker daemon
- Implement TLS mutual authentication
- Use private registries
- Enable image signing verification
- Implement RBAC
- Regular security audits
- Run docker-bench-security
Common Security Commands
Check Container Security
# View container capabilities docker inspect <container> | grep -A 20 "EffectiveCaps" # Check if running as root docker exec <container> id # View mounted volumes docker inspect <container> | grep -A 10 "Mounts" # Check security options docker inspect <container> | grep -A 10 "SecurityOpt"
Run Security Audit
# Install docker-bench-security git clone https://github.com/docker/docker-bench-security cd docker-bench-security ./docker-bench-security.sh
Image Signing
# Enable Docker Content Trust export DOCKER_CONTENT_TRUST=1 # Pull only signed images docker pull <image> # Backup signing keys tar -zcvf private_keys_backup.tar.gz ~/.docker/trust/private
Security Options Reference
--security-opt Options
# Prevent privilege escalation --security-opt=no-new-privileges:true # Disable seccomp (not recommended) --security-opt seccomp=unconfined # Custom seccomp profile --security-opt seccomp=/path/to/profile.json # Disable AppArmor (not recommended) --security-opt apparmor=unconfined # Custom AppArmor profile --security-opt apparmor=custom-profile # Disable SELinux (not recommended) --security-opt label:disable # Custom SELinux label --security-opt label=level:s0:c100,c200
Capability Management
# Drop all capabilities --cap-drop=all # Add specific capabilities --cap-add=NET_BIND_SERVICE --cap-add=CHOWN --cap-add=SETUID # Drop specific capabilities --cap-drop=NET_RAW --cap-drop=SYS_ADMIN
Alternative Runtimes
gVisor
Provides stronger isolation between application and host kernel:
# Install runsc # Use with Docker docker run --runtime=runsc <image>
Kata Containers
Uses lightweight VMs for stronger isolation:
# Install kata-runtime # Use with Docker docker run --runtime=kata <image>
Troubleshooting
Container Won't Start
# Check for capability issues docker inspect <container> | grep -i cap # Check for seccomp violations docker logs <container> # Check AppArmor/SELinux denials dmesg | grep -i apparmor dmesg | grep -i avc
Performance Issues
# Check resource limits docker stats <container> # Check cgroup limits cat /sys/fs/cgroup/memory/docker/<container-id>/memory.limit_in_bytes