Container Security Hardening: Docker, Kubernetes & Supply Chain
Complete container security guide — Dockerfile hardening, Trivy image scanning, Kubernetes Pod Security Standards, OPA Gatekeeper, runtime security with Falco, and software supply chain with cosign + SBOM.
Container Threat Model
Container security spans four layers: image (what's in it), registry (who can push/pull), runtime (what it can do), and supply chain (proving what you built is what deployed). Ignore any layer and you have a gap.
Dockerfile Hardening
# ❌ Insecure — common mistakes
FROM node:latest # mutable tag
COPY . /app # copies .env and secrets
RUN npm install # installs dev deps, runs as root
CMD ["node", "server.js"] # runs as root
# ✅ Hardened
FROM node:20.17.0-alpine3.20 # pinned + minimal OS
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --chown=node:node src/ ./src/
USER node # never root
EXPOSE 3000
CMD ["node", "--max-old-space-size=256", "src/server.js"]
Image Scanning Pipeline
Kubernetes Pod Security Standards
Apply the restricted PSS profile to all namespaces. It enforces non-root, read-only root filesystem, dropped capabilities, and seccomp profiles.
kubectl label namespace production pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/warn=restricted
---
# Compliant pod securityContext
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
seccompProfile: { type: RuntimeDefault }
capabilities: { drop: ["ALL"] }
Runtime Security with Falco
Falco monitors kernel syscalls to detect suspicious behavior at runtime — container spawning a shell, reading sensitive files, unexpected outbound connections. It's the IDS for your Kubernetes cluster.
# Alert if container spawns a shell
- rule: Shell spawned in container
condition: spawned_process and container and shell_procs
output: >
Shell in container
(user=%user.name img=%container.image.repository
cmd=%proc.cmdline)
priority: WARNING
Supply Chain Security with cosign
Sign images with cosign and use OPA Gatekeeper to reject pods whose images aren't signed by your CI pipeline. Even if an attacker gains registry access, they cannot deploy unsigned images.
# Sign with cosign (keyless, OIDC-based)
cosign sign --certificate-identity=https://github.com/org/app/.github/workflows/build.yml@refs/heads/main --certificate-oidc-issuer=https://token.actions.githubusercontent.com $ECR/$IMAGE:$TAG
# Verify before deployment
cosign verify --certificate-identity=... --certificate-oidc-issuer=... $ECR/$IMAGE:$TAG