Kubernetes Manifest Security Reference
Static analysis of raw K8s manifests (Deployment, StatefulSet, DaemonSet, Pod, etc.). For runtime cluster/image work, use the container-security skill.
Scanners
kubesec
# Scan single manifest
kubesec scan deployment.yaml
# stdin
cat deployment.yaml | kubesec scan -
# JSON output (score + rule breakdown)
kubesec scan deployment.yaml -o json
# Remote API (no local install needed)
curl -sSX POST --data-binary @deployment.yaml https://v2.kubesec.io/scankubesec returns a numeric score and per-rule advice. Use as a triage signal; pair with Checkov/kube-linter for specific rule IDs.
Checkov
checkov -d ./k8s-manifests --framework kubernetes
checkov -d ./kustomize --framework kustomizeTrivy config
trivy config ./k8s-manifests
# Severity gate
trivy config --severity HIGH,CRITICAL ./k8s-manifests
# Machine-readable output
trivy config -f json -o results.json ./k8s-manifestskube-linter
go install golang.stackrox.io/kube-linter/cmd/kube-linter@latest
# or: brew install kube-linter
kube-linter lint ./k8s-manifests
kube-linter lint ./k8s-manifests --format json
kube-linter lint ./k8s-manifests --config .kube-linter.yamlPolaris
brew install fairwinds/tap/polaris
polaris audit --audit-path ./k8s-manifests --format json > polaris.json
polaris audit --audit-path ./k8s-manifests --only-show-failed-testsPolaris returns a percentage score per workload; --only-show-failed-tests keeps the output terse.
Security Checklist
Pod / Container Security Context
-
runAsNonRoot: true -
runAsUserset to non-zero -
readOnlyRootFilesystem: true -
allowPrivilegeEscalation: false -
privileged: false -
capabilities.drop: ["ALL"], minimal explicitadd -
seccompProfile.type: RuntimeDefault(or stricter)
Resource Management
-
resources.limits.cpu/.memoryset -
resources.requests.cpu/.memoryset - No
hostPID: true - No
hostIPC: true - No
hostNetwork: true - No
hostPathvolumes (or tightly scoped read-only)
Network
- NetworkPolicies defined (default-deny baseline)
- Ingress TLS configured (no
http: truewithout TLS) - Service account tokens auto-mounted only when needed (
automountServiceAccountToken: false)
Images
- Images from trusted registries (private / signed)
- Image tags pinned (no
:latest) -
imagePullPolicy: Alwaysfor production - Image signing verified (cosign / Sigstore) — see container-security skill
RBAC
- Least privilege ServiceAccounts
- No
cluster-adminRoleBindings - Namespace-scoped Roles preferred over ClusterRoles
- No wildcard
verbs: ["*"]orresources: ["*"]
Inline Suppressions
metadata:
annotations:
# Checkov
checkov.io/skip1: CKV_K8S_8=Liveness probe not required for static service
# kube-linter
ignore-check.kube-linter.io/run-as-non-root: "Image requires root for legacy binary"