Home/Learn/Docker/Docker Security Best Practices

Docker Security Best Practices

Advanced
Security

Container security spans image hardening, runtime restrictions, secret management, and network policies. A misconfigured container can expose the host kernel to attack.

Overview

Docker's isolation is a user-space boundary, not a VM-level hardware boundary. Containers sharing the host kernel means a kernel exploit can break container isolation entirely. Defense in depth is essential: minimal base images (fewer packages = smaller attack surface), non-root users, read-only filesystems, dropped Linux capabilities, no privileged mode, proper secret management (never ENV for secrets in prod), and network segmentation. Security scanning must happen at build time (Trivy in CI) and continuously at runtime (Falco for anomaly detection).

Least Privilege — Drop Capabilities

Linux capabilities break root's all-or-nothing privilege model into fine-grained units. By default, Docker grants containers a subset of capabilities. You can drop all and add back only what the app needs.

bash/compose — capability dropping and read-only FS
# Drop all capabilities, add back only net_bind_service (port <1024)

docker run \

  --cap-drop=ALL \

  --cap-add=NET_BIND_SERVICE \

  --read-only \                    # read-only root filesystem

  --tmpfs /tmp \                   # writable temp dir in memory only

  --security-opt no-new-privileges \  # prevent setuid escalation

  --user 1000:1000 \               # non-root UID:GID

  nginx:alpine



# In docker-compose.yml:

services:

  api:

    cap_drop:

      - ALL

    cap_add:

      - NET_BIND_SERVICE

    read_only: true

    tmpfs:

      - /tmp

    security_opt:

      - no-new-privileges:true

    user: "1000:1000"

Secret Management — Never Use ENV in Production

Environment variables are visible in docker inspect, written to container metadata, and accessible to any process in the container. Use Docker Secrets (Swarm), mounted secret files, or a secrets manager (AWS Secrets Manager, Vault).

Secret management patterns
# ❌ BAD: secrets visible in docker inspect and child processes

docker run -e DATABASE_PASSWORD=supersecret myapp



# ❌ ALSO BAD: secrets baked into image layers

# Dockerfile:

# ENV DATABASE_PASSWORD=supersecret   ← visible in docker history



# ✅ Docker Swarm secrets (production)

echo "supersecret" | docker secret create db_password -

docker service create \

  --secret db_password \       # mounted as /run/secrets/db_password

  myapp



# In app code:

# const password = fs.readFileSync('/run/secrets/db_password', 'utf8').trim()



# ✅ AWS Secrets Manager at runtime

# Use AWS SDK to fetch secret at startup — not stored in image or env



# ✅ For Kubernetes: use Kubernetes Secrets mounted as files

# volumes:

#   - name: db-password

#     secret:

#       secretName: my-db-secret

# volumeMounts:

#   - name: db-password

#     mountPath: /run/secrets

#     readOnly: true

Never Use Privileged Mode

Running a container with --privileged gives it full access to all Linux capabilities and the host device tree — effectively root on the host. This is almost never needed.

Security anti-patterns to avoid
# ❌ NEVER do this in production:

docker run --privileged myapp     # full host root access — container escape = host compromise



# ❌ Avoid mounting the Docker socket (gives host Docker control):

docker run -v /var/run/docker.sock:/var/run/docker.sock myapp

# Anyone inside the container can now run: docker run --privileged -v /:/host alpine

# → full host filesystem access



# ✅ Instead of Docker socket, use:

# - Docker-in-Docker (dind) for CI that needs Docker

# - kaniko or buildah for rootless image building

# - Dedicated CI runners (GitHub Actions, GitLab CI)



# Scan for misconfigurations:

# docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \

#   aquasec/trivy config /path/to/Dockerfile

Key Points to Remember

  • 1Drop all Linux capabilities with --cap-drop=ALL and add back only what is needed.
  • 2--read-only makes the root filesystem immutable — attackers cannot write malware.
  • 3Never use ENV for secrets in production — they are visible in docker inspect and to all processes.
  • 4Never use --privileged mode — it gives container full host kernel access.
  • 5Never mount the Docker socket into a container — it enables full host Docker control.
  • 6Use Trivy or Docker Scout in CI to catch CVEs before pushing images to production.

Interview Questions

Sign in to ask Aria
1

What are Linux capabilities in the context of Docker security?

2

Why is mounting the Docker socket dangerous?

Ask Aria about Docker Security Best Practices

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…