Container Security Hardening Checklist
A container security hardening checklist is a set of practical controls that reduce risk from vulnerable images, insecure defaults, excessive privileges, and weak runtime isolation in containerized applications.
Container security hardening is most effective when you treat it as a lifecycle problem—secure the build, registry, deploy, and runtime, not just the image. This container security hardening checklist focuses on the highest-impact controls teams can standardize across Docker and Kubernetes.
How it works (hardening as a pipeline)
Hardening works best as a set of gates and guardrails:
- Build-time hygiene reduces what can go wrong (minimal base images, pinned versions, SBOMs).
- Pre-deploy checks prevent known-bad artifacts from reaching environments (scanning, signing, policy enforcement).
- Runtime restrictions limit blast radius when compromise happens (least privilege, read-only filesystems, seccomp/AppArmor, network policies).
- Monitoring and response detect drift and active exploitation (audit logs, runtime alerts, image provenance verification).
If you want a quick primer on supply-chain threats that commonly impact containerized environments, see: what is a supply chain attack.
Practitioner checklist (what to do next)
1) Image and build hardening (supply chain)
- Use minimal, trusted base images
- Prefer distroless/minimal OS images where feasible.
- Avoid
latesttags; pin by digest to prevent surprise updates. - Multi-stage builds to keep compilers/build tools out of final images.
- Remove secrets from images
- No API keys in
ENV, layers, or build args. - Use a secret manager or Kubernetes Secrets (and restrict access).
- Generate an SBOM (Software Bill of Materials)
- Store it with the image artifact so you can answer “what’s inside?” quickly.
- If your team is formalizing this practice, see what is software composition analysis for how SCA ties into dependency risk.
- Scan images for vulnerabilities and malware before pushing.
- Sign images and verify signatures at deploy time.
- Rebuild regularly
- A “secure” Dockerfile from six months ago is still risky if base layers are unpatched.
2) Registry and artifact controls
- Private registry access controls
- Enforce least privilege (read-only for deploy identities, write for CI only).
- Require MFA for human access where possible.
- Immutability and retention
- Prevent overwriting tags in production repositories.
- Keep enough history to investigate incidents.
- Admission checks (policy)
- Block unsigned images, unscanned images, and images from unapproved registries.
3) Runtime hardening (containers should be “boring”)
- Run as non-root
- Set a non-zero
USERin the Dockerfile and enforcerunAsNonRootin Kubernetes. - Drop Linux capabilities
- Start from “drop all” and add back only what’s required.
- Read-only root filesystem
- Mount writable paths explicitly (e.g.,
/tmp, app cache) with tight permissions. - No privileged containers
- Avoid
--privilegedandhostPID/hostNetwork/hostIPCunless doing node-level operations. - Limit resources
- CPU/memory limits reduce DoS impact and noisy-neighbor issues.
- Use seccomp + AppArmor/SELinux
- Default seccomp is better than none; tailored profiles are stronger.
- Avoid Docker socket mounts
- Mounting
/var/run/docker.sockis often equivalent to root on the host. - Keep containers immutable
- No SSH, no package installs at runtime. Rebuild and redeploy instead.
4) Kubernetes-specific guardrails (if you use K8s)
- Use namespaces and RBAC properly
- Separate environments; restrict service accounts; don’t rely on default service account permissions.
- Network policies
- Default-deny ingress/egress and allow only required flows.
- Pod Security
- Enforce baseline/restricted settings (e.g., no privilege escalation, non-root, seccomp).
- Secrets hygiene
- Restrict who can read Secrets; consider encryption at rest; avoid broad wildcard RBAC.
- Node hardening
- Patch nodes; restrict SSH; use minimal node images; protect kubelet endpoints.
5) Observability, logging, and detection
- Centralize logs
- Container stdout/stderr, ingress logs, and Kubernetes audit logs (if applicable).
- Detect drift
- Alert on new images, privilege changes, or unexpected network connections.
- Runtime threat detection
- Monitor for exec into containers, shell spawns, crypto-miner indicators, suspicious syscalls.
- Incident-ready forensics
- Preserve image digests, deployment manifests, and audit events to reconstruct what ran.
Technical notes: quick commands and patterns
Dockerfile hardening snippets
# Multi-stage build to keep toolchains out of runtime
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o app ./cmd/app
# Minimal runtime image
FROM gcr.io/distroless/static:nonroot
COPY --from=build /src/app /app
USER 65532:65532
ENTRYPOINT ["/app"]
Key checks:
- Non-root USER
- Minimal runtime base
- No package manager in final image
Docker runtime hardening example
docker run --rm \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
--cap-drop=ALL \
--security-opt no-new-privileges \
--pids-limit=256 \
--memory=512m \
--cpus=1 \
my-registry.example.com/myapp@sha256:...
Red flags to search for in Compose or run commands:
- privileged: true
- cap_add: ["SYS_ADMIN"] (or many capability adds)
- network_mode: host
- Mounts of /var/run/docker.sock or broad host paths like /
Kubernetes pod spec hardening example
apiVersion: v1
kind: Pod
metadata:
name: hardened-app
spec:
automountServiceAccountToken: false
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.com/app@sha256:...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop: ["ALL"]
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Operational notes:
- Prefer image digests over mutable tags.
- Disable service account token mounting unless needed.
- Use RuntimeDefault seccomp unless you have a tuned profile.
Log/audit patterns worth alerting on
- Kubernetes audit (high signal):
verb=createonpods/execverb=patchon workloads changingsecurityContext,hostNetwork,privileged- New
ClusterRoleBindingor broadRoleBindingtosystem:masters - Runtime indicators:
- Unexpected shell processes:
sh,bash,curl,wget - Outbound connections from normally “quiet” services
- Writes to unusual paths when root FS should be read-only
Example kubectl queries to spot risky settings:
# Find containers running privileged
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.name}{"="}{.securityContext.privileged}{" "}{end}{"\n"}{end}' | grep true
# Find pods with hostNetwork enabled
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.hostNetwork}{"\n"}{end}' | grep true
When you’ll encounter it
You’ll run into container hardening checklists when:
- Shipping microservices to production on Docker or Kubernetes and need consistent security baselines.
- Passing compliance reviews (SOC 2, ISO 27001) where you must demonstrate vulnerability management and least privilege.
- Responding to incidents involving exposed services, stolen registry credentials, or exploited dependencies.
- Standardizing platform engineering practices across teams to prevent “snowflake” container configs.
Tooling note (optional, pragmatic)
If your container workflows rely on developers working from untrusted networks (hotels, coworking spaces) or you routinely administer clusters from laptops, a reputable VPN can reduce exposure to opportunistic network attacks. If you already use one, keep it consistent and managed—options include NordVPN (Check NordVPN pricing →) or Surfshark (Try Proton VPN →). This isn’t a substitute for container hardening controls above, but it can be a helpful layer for admin traffic.
This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.
Related terms
Security configuration guidance for Docker and Kubernetes.
Inventory of components inside an image for risk and compliance.
Verifying who built an image and that it wasn’t tampered with.
Enforcing security rules before workloads run (e.g., blocking privileged pods).
Granting only the permissions/capabilities needed—no more.
Linux kernel and LSM controls that restrict process actions.
Rules that control pod-to-pod and pod-to-external traffic.
Detecting and preventing suspicious behavior after a container starts.