Docker Security Best Practices

4 Nov 2026, 11:2715 min readby ITYantra Admin

Complete guide to Docker security including image scanning, non-root users, capabilities, secrets, content trust, and runtime security.

# Docker Security Best Practices

Introduction

Docker security is critical for running containerized applications in production. Containers share the host kernel, so misconfigurations can lead to container escapes and host compromise. This tutorial covers image scanning, non-root users, Linux capabilities, secrets management, content trust, and runtime security.

Learning Objectives

By the end of this tutorial, you will be able to:

  • Scan Docker images for vulnerabilities
  • Run containers as non-root users
  • Manage Linux capabilities
  • Use Docker Secrets for sensitive data
  • Enable Docker Content Trust
  • Apply runtime security measures
  • Secure Docker daemon and networks

Technical Background

Docker Security Model

Host Kernel (shared by all containers)
    |
    +-- Container 1 (isolated via namespaces, cgroups)
    +-- Container 2 (isolated via namespaces, cgroups)
    |
    Docker Daemon (root by default)

Security Layers

| Layer | Controls | |-------|----------| | Image | Vulnerability scanning, signed images | | Build | Secure Dockerfile, no secrets in layers | | Runtime | Non-root, capabilities, seccomp, AppArmor | | Daemon | TLS, authentication, rootless mode | | Network | Network segmentation, firewall rules |

Prerequisites

  • Docker installed and running
  • Understanding of Linux security concepts

Hardware and Software Requirements

| Component | Requirement | |-----------|-------------| | Docker | v24+ | | Trivy or Docker Scout | For image scanning |

Step-by-Step Implementation

Phase 1: Image Scanning

#### Install and Use Trivy

# Install Trivy
sudo apt-get install -y wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main | sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install -y trivy

# Scan image
trivy image myapp:latest

# Scan with severity filter
trivy image --severity HIGH,CRITICAL myapp:latest

# Exit code on vulnerabilities
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest

#### Use Docker Scout

# Enable Docker Scout
docker scout cves myapp:latest
docker scout quickview myapp:latest

Phase 2: Run as Non-Root

#### Dockerfile with Non-Root User

FROM node:20-alpine

# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app
COPY --chown=appuser:appgroup . .

# Switch to non-root user
USER appuser

EXPOSE 3000
CMD ["node", "server.js"]

#### Run Container as Non-Root

# Run as specific user
docker run -u 1000:1000 myapp:latest

# Run with security options
docker run --read-only --tmpfs /tmp --cap-drop=ALL myapp:latest

Phase 3: Linux Capabilities

# Drop all capabilities, add only needed
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp:latest

# View container capabilities
docker run --rm myapp:latest capsh --print

# Add specific capability
docker run --cap-add=SYS_TIME myapp:latest

Phase 4: Docker Secrets

# Create secret
echo "supersecretpassword" | docker secret create db_password -

# List secrets
docker secret ls

# Inspect secret
docker secret inspect db_password

# Use secret in service (Docker Swarm)
docker service create \
  --name db \
  --secret db_password \
  -e MYSQL_PASSWORD_FILE=/run/secrets/db_password \
  mysql:8.0

#### Secrets in docker-compose

# docker-compose.yml
version: '3.8'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

Phase 5: Docker Content Trust

# Enable content trust
export DOCKER_CONTENT_TRUST=1

# Push signed image
docker push myregistry.com/myapp:latest

# Pull verified image
docker pull myregistry.com/myapp:latest

# Disable content trust
export DOCKER_CONTENT_TRUST=0

Phase 6: Runtime Security

# Run with seccomp profile
docker run --security-opt seccomp=profile.json myapp:latest

# Run with AppArmor profile
docker run --security-opt apparmor=docker-restricted myapp:latest

# Run with no new privileges
docker run --security-opt no-new-privileges:true myapp:latest

# Limit memory and CPU
docker run --memory="256m" --cpus="0.5" myapp:latest

# Prevent privilege escalation
docker run --security-opt no-new-privileges --cap-drop=ALL myapp:latest

Phase 7: Docker Daemon Security

#### Configure TLS for Docker Daemon

# Generate CA key and certificate
openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

# Generate server key and certificate
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=docker-host" -new -key server-key.pem -out server.csr
echo subjectAltName = DNS:docker-host,IP:192.168.1.10 > extfile.cnf
echo extendedKeyUsage = serverAuth >> extfile.cnf
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out server-cert.pem -extfile extfile.cnf

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

#### Rootless Docker

# Install rootless Docker
curl -fsSL https://get.docker.com/rootless | sh

# Set up environment
export PATH=/home/user/bin:$PATH
export DOCKER_HOST=unix:///home/user/docker.sock

# Start rootless Docker
dockerd-rootless.sh &

Phase 8: Network Security

# Create isolated network
docker network create --driver bridge --opt com.docker.network.bridge.enable_ip_masquerade=true secure-network

# Run container on isolated network
docker run -d --network secure-network --name web myapp:latest

# Inspect network
docker network inspect secure-network

Expected Output

  • Images scanned for vulnerabilities
  • Containers running as non-root
  • Linux capabilities managed
  • Secrets configured
  • Content trust enabled
  • Runtime security applied

Verification Procedures

| Check | Command | Expected Result | |-------|---------|-----------------| | Image scan | `trivy image myapp:latest` | No HIGH/CRITICAL vulnerabilities | | User check | `docker exec myapp whoami` | Non-root user | | Capabilities | `docker exec myapp capsh --print` | Limited capabilities | | Secrets | `docker secret ls` | Secrets listed | | Content trust | `docker pull --disable-content-trust=false myapp:latest` | Signed image verified |

Troubleshooting Scenarios

| Issue | Diagnosis | Resolution | |-------|-----------|------------| | Permission denied | Non-root user can't write to volume | Fix volume ownership; use user flag | | Port binding fails | Missing NET_BIND_SERVICE capability | Add --cap-add=NET_BIND_SERVICE | | Secret not found | Secret not created or wrong name | Create secret; verify name | | Content trust fails | Unsigned image | Sign image or disable trust for specific registry |

Best Practices

  • **Scan all images:** Integrate scanning into CI/CD pipeline
  • **Run as non-root:** Never run containers as root in production
  • **Use minimal base images:** Alpine, distroless, or scratch
  • **Drop all capabilities:** Add only what's needed
  • **Use secrets:** Never hardcode passwords or API keys
  • **Enable content trust:** Verify image integrity
  • **Limit resources:** Set memory and CPU limits
  • **Use rootless Docker:** Run daemon as non-root

Security Considerations

  • **Kernel sharing:** Containers share host kernel; kernel exploits affect all containers
  • **Daemon access:** Docker daemon runs as root; secure daemon socket
  • **Image supply chain:** Verify base images and dependencies
  • **Registry security:** Use private registries with authentication
  • **Network isolation:** Segment container networks
  • **Audit logging:** Log Docker daemon and container events

Conclusion

Docker security requires defense in depth across image, build, runtime, and daemon layers. By scanning images, running as non-root, managing capabilities, using secrets, enabling content trust, and applying runtime security, you can significantly reduce the risk of container escapes and host compromise.

References

  • Docker Security: https://docs.docker.com/engine/security/
  • Docker Bench Security: https://github.com/docker/docker-bench-security
  • Trivy: https://github.com/aquasecurity/trivy
  • Docker Content Trust: https://docs.docker.com/engine/security/trust/
  • Rootless Docker: https://docs.docker.com/engine/security/rootless/
#runtime-security#content-trust#secrets#capabilities#non-root#image-scanning#security#Docker