Introduction
Kubernetes Pod Security in 2026 is dominated by three policy engines — Pod Security Admission (PSA, the built-in successor to PodSecurityPolicy), Kyverno, and OPA Gatekeeper. They overlap in scope but diverge in expressive power, operational model, and ecosystem maturity. Choosing among them — or running them together — defines the security posture of every workload on the cluster.
This guide is a comparative analysis for platform engineers and security architects responsible for the policy layer of a production Kubernetes platform. We cover what each engine does, how they differ, when to use which, the migration story from deprecated PSP, and a recommended composition pattern for enterprises that need both the simplicity of PSA and the expressiveness of Kyverno.
Background: From PSP to PSA
PodSecurityPolicy (PSP) was Kubernetes’ original cluster-level admission control for pod security. It was deprecated in v1.21 (April 2021) and removed in v1.25 (August 2022). The replacement strategy split the role into two parts: a built-in admission controller (PSA) for the common cases, and pluggable policy engines (Kyverno, OPA Gatekeeper) for everything else.
PSP was removed because it had three structural problems: it was a cluster-singleton resource that could not be namespaced easily, its policy model (allow/deny on capabilities) did not compose well, and it had no obvious extension point for non-pod resources. The replacement model addresses all three.
Theory: Pod Security Admission
PSA is a Kubernetes-native admission controller that applies one of three pre-defined Pod Security Standards to a namespace:
- privileged — permissive; allows anything. Used for system namespaces.
- baseline — blocks the most egregious misconfigurations: host network, host PID, privileged containers, hostPath, dangerous capabilities. Still permissive enough for most legacy apps to run.
- restricted — the target posture: runAsNonRoot, runAsUser>0, no privilege escalation, seccomp default, capabilities all dropped.
Each profile can be applied at three enforcement levels: enforce (reject violating pods), audit (log violations), warn (return a warning to the user).
Configuration is via namespace labels:
apiVersion: v1
kind: Namespace
metadata:
name: payments
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Strengths of PSA: built into Kubernetes (no extra controller to install), predictable, well-documented, the standard fallback when more sophisticated policy is unavailable.
Limitations: only three profiles; no policy composition; no resource types other than pods; no mutation; no parameterisation. Pod-escape classes that abuse capabilities the baseline profile still allows (CAP_SYS_PTRACE, CAP_NET_ADMIN under certain conditions) are a case in point — baseline does not block them, and PSA gives no way to add the missing check without escalating the entire namespace to restricted.
Theory: Kyverno
Kyverno is a CNCF-graduated policy engine designed specifically for Kubernetes. Policies are YAML, declarative, validate-or-mutate-or-generate-or-cleanup, namespaced or cluster-scoped, with native support for any Kubernetes resource type.
Kyverno’s policy philosophy: stay close to Kubernetes idioms. Policies look like the resources they govern, with selectors that match the standard Kubernetes label and annotation patterns.
Three categories of Kyverno policy:
- Validate — pattern-match the resource; reject if it does not conform.
- Mutate — modify the resource before admission (add default labels, inject sidecars, set resource limits).
- Generate — create related resources (a NetworkPolicy when a namespace is created, a default ResourceQuota).
Kyverno also supports image verification (Cosign signature checks), policy reports, exception management, and a separate “cleanup” policy type for resource lifecycle.
Theory: OPA Gatekeeper
OPA Gatekeeper is the Kubernetes-specific integration of the Open Policy Agent project. Policies are written in Rego, a declarative policy language with set-theoretic semantics.
The Gatekeeper architecture has two parts:
- ConstraintTemplates — define a parameterised policy in Rego.
- Constraints — instantiate a ConstraintTemplate with specific parameters and scope.
This separation lets a platform team author ConstraintTemplates once (e.g., “containers must come from allowed registries”) and application teams instantiate Constraints with their own parameters (“our allowed registries are ecr.our-org/* and gcr.io/our-project/*“).
Gatekeeper’s strengths: Rego is more expressive than Kyverno’s pattern-matching for complex policies; OPA has reach beyond Kubernetes (Envoy, Terraform, CI/CD); the ConstraintTemplate model encourages reusable policy libraries.
Gatekeeper’s friction: Rego has a learning curve; debugging Rego is harder than debugging Kyverno YAML; policy violations report cryptic messages without effort to template good error text.
Technical Deep Dive: Kyverno vs Gatekeeper for a Specific Policy
Compare implementations of “all containers must drop ALL capabilities and explicitly add only what they need.”
Kyverno:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-drop-all
spec:
validationFailureAction: Enforce
rules:
- name: must-drop-all
match:
any:
- resources:
kinds: [Pod]
validate:
message: "All containers must drop ALL capabilities"
pattern:
spec:
containers:
- securityContext:
capabilities:
drop: ["ALL"]
Gatekeeper:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8spsprequiredropall
spec:
crd:
spec:
names:
kind: K8sPSPRequireDropAll
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8spsprequiredropall
violation[{"msg": msg}] {
c := input.review.object.spec.containers[_]
not has_drop_all(c)
msg := sprintf("Container %v must drop ALL capabilities", [c.name])
}
has_drop_all(c) {
c.securityContext.capabilities.drop[_] == "ALL"
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPRequireDropAll
metadata:
name: require-drop-all
spec:
match:
kinds:
- apiGroups: [""]
kinds: [Pod]
Kyverno’s version is shorter and more readable. Gatekeeper’s version is more expressive — it could trivially be extended to per-container exception logic, complex parent-resource lookups, or cross-resource correlations that would be awkward in Kyverno.
Technical Deep Dive: Performance and Failure Modes
Policy engines sit on the critical path of every admission request. Their latency and availability directly affect cluster usability.
PSA: in-process with kube-apiserver, sub-millisecond, no failure mode beyond apiserver failure itself.
Kyverno: separate controller, 1-10 ms per evaluation in typical configurations. Failure mode: if the Kyverno webhook is unreachable, admission either fails closed (rejecting everything) or fails open (allowing everything), depending on failurePolicy. Fail-closed is the safer default but can cause cluster-wide deploy outages if Kyverno itself crashes.
Gatekeeper: similar latency profile. Same failurePolicy considerations.
Mitigation patterns:
- Exempt critical system namespaces (kube-system, ingress-controllers, the policy engine’s own namespace) from policy.
- Run the policy engine with replicas across multiple nodes.
- Monitor webhook latency and policy-evaluation duration as SLOs.
- Have a documented “policy bypass” runbook for incident scenarios.
Practical Implementation: A Layered Composition
A defensible 2026 stack composes the engines:
- PSA enforce=restricted on all application namespaces. This is the safety net.
- Kyverno for the majority of org-specific policies (signed images, allowed registries, required labels, automatic NetworkPolicy generation, sidecar injection).
- Gatekeeper for the small set of policies that require Rego’s expressive power (cross-resource queries, complex parameterisation).
- Falco / Tetragon at runtime to catch what admission missed.
PSA being the safety net matters because Kyverno and Gatekeeper, if misconfigured or unavailable, can fail open. PSA being in-process means it cannot fail open without a kube-apiserver failure.
Practical Implementation: The Migration Path
For a cluster still on baseline PSA or with no admission policy beyond defaults:
Phase 1: Audit. Set every namespace to pod-security.kubernetes.io/audit: restricted. The apiserver will log every workload that would violate restricted, without rejecting any. Run for 2-4 weeks; collect the report.
Phase 2: Per-namespace decision. For each namespace, decide: can we enforce restricted? Or do we need an exception? Document each exception with the business reason and a remediation plan.
Phase 3: Enforce. Flip namespaces from audit to enforce one at a time, starting with the lowest-risk (new namespaces, dev environments).
Phase 4: Compensating policies via Kyverno. For namespaces that cannot enforce restricted, write Kyverno policies that close the specific gaps.
Phase 5: Advanced policies. Image signing enforcement, required resource limits, mandatory liveness probes, namespace-level NetworkPolicy autogeneration.
Technical Deep Dive: Image Verification
Image verification is the highest-leverage admission policy beyond pod security. The pattern: containers may only run if the image is signed by an approved key, with provenance attached.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signatures
spec:
validationFailureAction: Enforce
webhookTimeoutSeconds: 30
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "registry.ringsafe.in/*"
attestors:
- entries:
- keyless:
subject: "https://github.com/ringsafe/*/.github/workflows/release.yml@refs/heads/main"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: https://rekor.sigstore.dev
This policy enforces that any image from registry.ringsafe.in must have been signed by a GitHub Actions workflow on the main branch of an org-owned repository, with the signature recorded in Sigstore Rekor for transparency.
Enterprise Use Cases
Indian fintech platforms. Banking workloads on Kubernetes are increasingly running under PSA restricted + Kyverno image-signing policies + Cilium L7 NetworkPolicies. This baseline is what regulators are looking for in CSCRF maturity assessments.
SaaS multi-tenancy. Tenant workloads run with PSA restricted in their own namespaces; the SaaS provider’s control-plane uses Kyverno mutations to inject required tenant-isolation sidecars; Gatekeeper enforces complex tenant-quota policies.
Government and PSU platforms. Air-gapped clusters use Kyverno for image-signing against an internal Cosign root, ensuring no externally-pulled images can run.
Common Pitfalls
- Permanent baseline. Baseline was a migration target, not an end state. Treating it as the cluster’s permanent posture leaves you exposed to CVEs like the recent containerd flaw.
- Audit forever. Policies in audit mode catch nothing. They produce reports nobody reads. Enforce or remove.
- Running Kyverno and Gatekeeper for the same policy. Operational redundancy with no benefit; pick one engine per policy domain.
- Webhook fails open. A Kyverno webhook with
failurePolicy: Ignoredefeats its own purpose during the moments that matter (when the engine itself is under attack or stress). - Forgetting CronJobs and Jobs. Many security policies target Deployments and miss batch workloads.
- System namespaces forgotten. Privileged pods in kube-system are normal; the same workloads in application namespaces are not.
Action Items
- Run
kubectl get ns -o jsonpath='{.items[*].metadata.labels.pod-security.kubernetes.io/enforce}'to inventory current PSA posture across namespaces. - Enable
pod-security.kubernetes.io/audit: restrictedon every namespace currently below restricted. - Install Kyverno in a non-production cluster, apply the OWASP Kubernetes policy set, observe.
- Pick one image registry and require Cosign-signed images for it via Kyverno.
- Define your policy-engine SLOs (webhook latency p99 < 50ms, availability >= 99.9%).
- Document the policy bypass runbook for incident scenarios; rehearse it.
Kubernetes pod security in 2026 is no longer a “pick a tool” question — PSA, Kyverno, and Gatekeeper each have a role in a layered defence. The teams that compose them deliberately, audit honestly, and enforce decisively are the ones with cluster postures that survive both regulatory scrutiny and active attack.
Get a cloud posture review
IAM hardening, public-exposure mapping, IaC review, K8s audit. We map your actual blast radius — not what a CSPM dashboard guesses at.