Activate when building Dockerfiles, configuring container runtimes, reviewing container configurations, or deploying containers to any environment. Activate when security is mentioned in a container context. Provides defense-in-depth container security guidance.
Containers are not VMs. They share a kernel. Security must be intentional.
| Trigger | Action |
|---|---|
| Writing or reviewing a Dockerfile | Apply Dockerfile security rules |
| Deploying containers | Check runtime security configuration |
| Choosing base images | Apply image selection criteria |
| Setting up CI/CD for containers | Apply supply chain security |
| Container security review requested | Run full checklist |
alpine, distroless, or scratch — NOT or unless you need specific packagesubuntudebianFROM node:20-alpine@sha256:abc123... — tags can be overwrittenlatest in production — it's a moving target# GOOD: Security-conscious Dockerfile
# Pin to digest
FROM node:20-alpine@sha256:abc123... AS builder
# Don't run as root
RUN addgroup -g 1001 -S app && adduser -u 1001 -S app -G app
# Copy only what's needed (after .dockerignore)
COPY package*.json ./
RUN npm ci --only=production
COPY --chown=app:app . .
# Use non-root user
USER app
# Don't expose unnecessary ports
EXPOSE 3000
# Use exec form (not shell form) for proper signal handling
CMD ["node", "server.js"]
| Rule | Reason |
|---|---|
USER app (non-root) | Root in container = root escape risk |
| Multi-stage builds | Build tools don't ship to production |
.dockerignore with .git, .env, node_modules | Prevents secret leakage into image |
COPY specific files, not COPY . . blindly | Minimize attack surface, prevent accidental secret inclusion |
No apt-get install without --no-install-recommends | Minimizes installed packages |
RUN rm -rf /var/lib/apt/lists/* after installs | Reduces image size and cached package data |
| No secrets in build args or ENV | Build args are visible in image history |
HEALTHCHECK instruction present | Enables proper container lifecycle management |
ENV, ARG, or COPY — they persist in image layersRUN --mount=type=secret,id=mysecret ...trufflehog, gitleaks)--read-only — prevents runtime modification of the container
/tmp, /var/log)securityContext:
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"] # Only if needed
allowPrivilegeEscalation: falserunAsNonRoot: true + runAsUser: 1001RuntimeDefault at minimum
securityContext:
seccompProfile:
type: RuntimeDefault
| Setting | Risk | Exception |
|---|---|---|
privileged: true | Full host access | Almost never. CNI plugins, specific system tools only |
hostNetwork: true | Bypasses network isolation | Monitoring agents that need host network visibility |
hostPID: true | Can see/kill host processes | Never in application workloads |
hostPath volumes | Access to host filesystem | Only for DaemonSets that need host access (logging, monitoring) |
SYS_ADMIN capability | Near-root privilege | Never in application containers |
# Kyverno policy example
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-image-digest
spec:
rules:
- name: check-digest
match:
resources:
kinds: ["Pod"]
validate:
message: "Images must use digests, not tags"
pattern:
spec:
containers:
- image: "*@sha256:*"
If a container is suspected compromised:
kubectl logs, kubectl describe pod, container filesystem