Security Hardening Scanning DevSecOps
2026 · Container Security Best Practices
Containers share the host kernel -- a misconfigured container can compromise the entire host. Security must be addressed at every layer: image, build, runtime, network, and orchestration.
Privileged containers or kernel exploits can break isolation boundaries
Malicious base images or compromised dependencies injected at build time
Secrets, credentials, and sensitive data leaked through images or logs
According to Sysdig's 2025 Container Security Report, 87% of container images contain high or critical vulnerabilities.
/var/run/docker.sock)Start with minimal base images and scan every layer for known CVEs before deployment.
alpine, distroless, or chainguard images:latest -- use explicit versions# Scan an image with Trivy
trivy image --severity HIGH,CRITICAL myapp:latest
# Scan with Snyk
snyk container test myapp:latest --severity-threshold=high
rm -rf /var/cache/apt/*COPY instead of ADD.dockerignore fileHEALTHCHECK instructionsENV or ARGapt-get upgrade (non-reproducible):latest tags for base imageschmod 777 anywhere# Multi-stage build example
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM gcr.io/distroless/nodejs20-debian12
COPY --from=builder /app /app
USER nonroot
CMD ["app/server.js"]
By default, containers run as root (UID 0). If an attacker escapes the container, they have root on the host. Always run as a non-root user.
# Create a dedicated user
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
# Set ownership and switch
COPY --chown=appuser:appgroup . /app
USER appuser
# Override user at run time
docker run --user 1000:1000 myapp
# Verify running user
docker exec mycontainer whoami
# Output: appuser
# Check with id
docker exec mycontainer id
# uid=1000 gid=1000
Tip: Use --user flag even if the Dockerfile sets USER -- defence in depth.
Prevent attackers from writing malicious files, scripts, or binaries into the container filesystem at runtime.
# Run with read-only root filesystem
docker run --read-only myapp
# Allow specific writable paths with tmpfs
docker run --read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
--tmpfs /var/run:rw,noexec,nosuid \
myapp
/tmp or log dirstmpfs mounts with noexec flag--no-new-privilegesNever bake secrets into images. Use runtime secret injection mechanisms to provide credentials securely.
ENV DB_PASS=s3cret
# Visible in image history!
# docker history myimg
echo "s3cret" | docker \
secret create db_pass -
# Mounted at /run/secrets/
# in-memory tmpfs, never on disk
# syntax=docker/dockerfile:1
RUN --mount=type=secret,\
id=mysecret \
cat /run/secrets/mysecret
Production: Use external vaults -- HashiCorp Vault, AWS Secrets Manager, Azure Key Vault -- and inject at runtime via environment or mounted files.
Docker grants containers a subset of Linux capabilities by default. Reduce the attack surface by dropping all and adding only what is needed.
# Drop all capabilities, add only needed
docker run --cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--cap-add=CHOWN \
myapp
# NEVER use --privileged in production
# It grants ALL 40+ capabilities
# Use Docker's default seccomp profile
# (blocks ~44 of 300+ syscalls)
# Apply a custom profile
docker run --security-opt \
seccomp=custom-profile.json \
myapp
# Check current profile
docker inspect --format \
'{{.HostConfig.SecurityOpt}}' ctr
| Capability | Purpose | Risk if Granted |
|---|---|---|
SYS_ADMIN | Mount filesystems, namespaces | Critical -- near root |
NET_RAW | Raw sockets, ping | Network spoofing |
SYS_PTRACE | Debug processes | Process injection |
NET_BIND_SERVICE | Bind ports <1024 | Low risk |
Mandatory Access Control (MAC) systems add a kernel-level enforcement layer beyond standard Unix permissions.
docker-default profile automatically# Apply custom AppArmor profile
docker run --security-opt \
apparmor=my-custom-profile \
myapp
container_t type# Run with SELinux labelling
docker run --security-opt \
label=type:container_t \
myapp
# Disable (not recommended)
# --security-opt label=disable
By default, all containers on the same bridge network can communicate. Use network segmentation to enforce least-privilege communication.
# Create isolated networks
docker network create --internal backend
docker network create frontend
# Frontend can reach internet
docker run --network frontend web
# Backend is internal-only
docker run --network backend db
--icc=false in daemon config--network=none for offline containers0.0.0.0:2375-p 127.0.0.1:8080:80# docker-compose.yml -- network isolation
services:
web:
networks: [frontend, backend]
api:
networks: [backend]
db:
networks: [backend]
networks:
frontend:
backend:
internal: true
Verify that images have not been tampered with between build and deployment using cryptographic signatures.
# Enable content trust globally
export DOCKER_CONTENT_TRUST=1
# Push a signed image
docker push myregistry/myapp:v1.2
# Pull only signed images
docker pull myregistry/myapp:v1.2
# Fails if unsigned!
# Generate a key pair
cosign generate-key-pair
# Sign an image
cosign sign --key cosign.key \
myregistry/myapp@sha256:abc...
# Verify before deployment
cosign verify --key cosign.pub \
myregistry/myapp@sha256:abc...
Best Practice: Enforce signature verification in your CI/CD pipeline and admission controllers (e.g., Kyverno, OPA Gatekeeper).
Detect anomalous behaviour in running containers -- unexpected processes, file access, network connections, and syscalls.
# Falco rule example -- detect shell spawned in container
- rule: Terminal Shell in Container
desc: Detect a shell spawned in a container
condition: >
spawned_process and container and proc.name in (bash, sh, zsh)
output: "Shell spawned in container (user=%user.name container=%container.name)"
priority: WARNING
An open-source script that checks your Docker host and containers against the CIS Docker Benchmark -- dozens of automated checks.
# Run Docker Bench for Security
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 -v /etc:/etc:ro \
docker/docker-bench-security
[PASS] 1.1 - Linux Kernel >= 4.x
[WARN] 2.1 - Restrict network traffic
[PASS] 4.1 - Image has non-root user
[WARN] 5.4 - Privileged containers
[INFO] 7.1 - Swarm mode enabled
Your container registry is a critical supply chain component. Secure it like any production system.
| Registry | Scanning | Signing | RBAC |
|---|---|---|---|
| Docker Hub | Docker Scout | DCT / Cosign | Teams & Orgs |
| GitHub GHCR | Dependabot | Cosign | Org-level |
| AWS ECR | Inspector | Cosign / Notation | IAM Policies |
| Harbor (OSS) | Trivy built-in | Cosign / Notation | Fine-grained |
Secure every link in the chain from source code to running container using SLSA and SBOM frameworks.
syft, trivy, or docker sbom# Generate SBOM with Syft
syft myapp:latest -o spdx-json > sbom.spdx.json
# Attach SBOM attestation with Cosign
cosign attest --predicate sbom.spdx.json --type spdxjson \
--key cosign.key myregistry/myapp@sha256:abc...
Run the entire Docker daemon and containers without root privileges -- eliminating the most dangerous attack vector.
user namespaces for UID remappingslirp4netns or pasta for networking# Install rootless Docker
dockerd-rootless-setuptool.sh install
# Verify rootless mode
docker info --format '{{.SecurityOptions}}'
# Output includes "rootless"
# Set environment for rootless
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
The CIS Docker Benchmark provides a comprehensive set of recommendations for securing Docker in production.
| Section | Key Recommendations | Priority |
|---|---|---|
| 1. Host Config | Keep host OS and Docker up to date, audit Docker files | Critical |
| 2. Daemon Config | Enable user namespace support, restrict network traffic | Critical |
| 3. Config Files | Set ownership/permissions on daemon files to root:root | High |
| 4. Images | Use trusted base images, scan for vulnerabilities, no secrets | Critical |
| 5. Runtime | No privileged containers, drop capabilities, read-only FS | Critical |
| 6. Operations | Avoid image sprawl, use centralised logging | High |
| 7. Swarm | Encrypt overlay networks, rotate join tokens | Medium |
Automation: Use docker-bench-security and integrate CIS checks into CI/CD pipelines.