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.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/linux-hardening/privilege-escalation/docker-security/docker-security/SKILL.MD
source content

Docker 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

FeaturePurposeDefaultRecommended
--read-only
Prevents filesystem writesDisabledEnable
--security-opt=no-new-privileges:true
Blocks privilege escalationDisabledEnable
--cap-drop=all
Drops all Linux capabilitiesPartial dropDrop all, add only needed
--user
Run as non-rootRootNon-root user
--memory
Memory limitUnlimitedSet appropriate limit
--cpus
CPU limitUnlimitedSet appropriate limit
--pids-limit
Process limitUnlimitedSet 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:
    container_t
    can only interact with
    container_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-PatternRiskFix
FROM image:latest
Unpredictable buildsPin specific version
USER root
Full container compromiseUse non-root user
ADD http://...
Supply chain attackUse COPY
ENV SECRET=...
Secrets in imageUse secrets management
--privileged
Host escapeRemove flag
No resource limitsDoS attacksSet memory/CPU limits
No health checkZombie containersAdd 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

References