Security Error Guide: Kubernetes 'admission webhook denied' Pod Security
Fix Kubernetes admission-webhook denials from Pod Security Standards, Kyverno, or Gatekeeper: read the denial, find the failing control, and fix the pod spec securely.
- #security
- #hardening
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
Kubernetes admission control evaluates every object before it is persisted. Security policy engines — the built-in Pod Security Admission (PSA) enforcing the Pod Security Standards, or validating webhooks like Kyverno and OPA Gatekeeper — reject workloads that violate hardening rules such as “no privileged containers” or “must run as non-root.” When a pod (or its controller) is rejected, the apiserver returns an admission error and the pod is never created. This is the guardrail working: an over-privileged pod should be blocked. But the same denial appears when a legitimate workload’s security context simply hasn’t been set to satisfy the policy.
The literal error from the built-in Pod Security Admission:
Error creating: pods "web-7d9f" is forbidden: violates PodSecurity "restricted:latest":
allowPrivilegeEscalation != false (container "web" must set securityContext.allowPrivilegeEscalation=false),
unrestricted capabilities (container "web" must set securityContext.capabilities.drop=["ALL"]),
runAsNonRoot != true (pod or container "web" must set securityContext.runAsNonRoot=true),
seccompProfile (pod or container "web" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
A validating webhook (Kyverno/Gatekeeper) phrases it as a webhook denial:
Error from server: admission webhook "validate.kyverno.svc-fail" denied the request:
policy Pod/default/web-7d9f for resource violation: require-run-as-nonroot:
autogen-check-runAsNonRoot: 'validation error: Running as root is not allowed. rule autogen-check-runAsNonRoot failed'
When a Deployment is the parent, the pod-level denial surfaces on the ReplicaSet event, not the Deployment, so kubectl get pods shows nothing and the Deployment reports unavailable replicas.
Symptoms
kubectl applyof a bare pod returnsforbidden: violates PodSecurityoradmission webhook ... denied the request.- A Deployment/StatefulSet stays at 0 ready replicas with no pods; the ReplicaSet events show the denial.
- The workload deployed fine in a
privileged/baselinenamespace but fails after moving to arestrictedone. - Only creation/update is blocked; existing pods keep running (enforcement is at admission time).
kubectl -n prod get events --field-selector reason=FailedCreate --sort-by=.lastTimestamp | tail -5
... FailedCreate replicaset/web-7d9f Error creating: pods "web-..." is forbidden: violates PodSecurity "restricted:latest": ...
kubectl -n prod get ns prod -o jsonpath='{.metadata.labels}' | tr ',' '\n' | grep pod-security
"pod-security.kubernetes.io/enforce":"restricted"
Common Root Causes
1. Missing non-root and privilege-escalation settings (PSS restricted)
The restricted profile requires runAsNonRoot: true, allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], and a seccomp profile. A default pod spec sets none of these.
kubectl -n prod get events --field-selector reason=FailedCreate -o jsonpath='{.items[-1:].message}'
... must set securityContext.runAsNonRoot=true ... allowPrivilegeEscalation=false ...
2. Privileged or host-namespace request
The pod sets securityContext.privileged: true, hostNetwork, hostPID, hostIPC, or hostPath volumes that baseline/restricted forbid.
kubectl apply -f pod.yaml --dry-run=server
... violates PodSecurity "baseline:latest": privileged (container "x" must not set securityContext.privileged=true), host namespaces (hostNetwork=true)
3. A Kyverno/Gatekeeper policy the workload doesn’t satisfy
A custom validating policy (e.g., require resource limits, disallow latest tag, require a registry allowlist) rejects the spec.
kubectl get clusterpolicies # Kyverno
kubectl get constraints # Gatekeeper
4. Namespace enforce label stricter than the workload
The namespace was labeled enforce: restricted (or a webhook applied cluster-wide) while the workload was written for a looser standard.
5. Adding a capability the policy blocks
The container requests capabilities.add: ["NET_ADMIN"] or SYS_ADMIN, which restricted (and most policies) disallow.
6. Webhook failurePolicy=Fail with the webhook unavailable
The policy webhook is down and its failurePolicy: Fail blocks all matching creates — a denial that is really an availability problem.
Diagnostic Workflow
Step 1: Read the full denial message
kubectl apply -f pod.yaml --dry-run=server 2>&1
# for controllers, read the child event:
kubectl -n prod describe replicaset -l app=web | sed -n '/Events/,$p'
The message lists every failing control by name — treat it as your checklist.
Step 2: Identify which policy engine denied it
# Built-in PSA?
kubectl get ns prod -o jsonpath='{.metadata.labels}' | tr ',' '\n' | grep pod-security
# Kyverno / Gatekeeper webhooks?
kubectl get validatingwebhookconfigurations
kubectl get clusterpolicies 2>/dev/null; kubectl get constraints 2>/dev/null
Step 3: Test against the target standard before deploying
kubectl label ns scratch \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/warn=restricted --overwrite
kubectl -n scratch apply -f pod.yaml # see warnings/denials without touching prod
Step 4: Add the required securityContext
Set the fields the message named, at pod and/or container level:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: web
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
runAsNonRoot: true
Step 5: Re-apply and confirm
kubectl apply -f pod.yaml
kubectl -n prod get pods -l app=web
Example Root Cause Analysis
A team migrates a Deployment into a namespace that platform engineering just relabeled pod-security.kubernetes.io/enforce=restricted. The Deployment reports 0/3 ready replicas, and kubectl get pods shows nothing at all — because the pods are rejected at admission, so they never appear.
The denial lives on the ReplicaSet event:
kubectl -n prod get events --field-selector reason=FailedCreate -o jsonpath='{.items[-1:].message}{"\n"}'
Error creating: pods "web-7d9f-..." is forbidden: violates PodSecurity "restricted:latest":
allowPrivilegeEscalation != false ..., unrestricted capabilities ..., runAsNonRoot != true ...,
seccompProfile ... must set securityContext.seccompProfile.type to "RuntimeDefault"
The container image runs fine as non-root, but the Deployment’s pod template never declared a securityContext, so it fails four restricted controls at once. The policy is correct; the manifest just predates the stricter namespace.
Fix: add the required security context to the pod template (not a one-off pod) so the controller’s future pods comply:
# spec.template.spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
seccompProfile: { type: RuntimeDefault }
# spec.template.spec.containers[].securityContext:
allowPrivilegeEscalation: false
capabilities: { drop: ["ALL"] }
kubectl apply -f deploy.yaml
kubectl -n prod rollout status deploy/web
deployment "web" successfully rolled out
The pods now satisfy the restricted standard and schedule normally — hardened, not exempted.
Prevention Best Practices
- Bake a compliant
securityContext(non-root, drop ALL caps, no privilege escalation,RuntimeDefaultseccomp) into every pod template and Helm chart baseline sorestrictedis the default, not a retrofit. - Test manifests against the target standard in CI or a scratch namespace with
warn/auditlabels before enforcing, so denials surface pre-merge. - Roll out Pod Security Standards progressively:
warn+auditfirst, thenenforce, and read audit annotations to find non-compliant workloads before flipping enforcement. - Prefer fixing the workload over granting exemptions; if a pod genuinely needs a capability or host access, scope a narrow, documented exception rather than dropping the namespace to
baseline. - Set validating-webhook
failurePolicydeliberately and monitor webhook availability, so a down policy engine doesn’t masquerade as a flood of denials. - Use the pod-level denial events on ReplicaSets/Jobs (not just the Deployment) when debugging “0 replicas, no pods.” The free incident assistant can group
FailedCreateadmission denials by failing control and suggest the securityContext to add.
Quick Command Reference
# Server-side dry run shows the denial without persisting
kubectl apply -f pod.yaml --dry-run=server
# Find admission denials behind a controller
kubectl -n <ns> get events --field-selector reason=FailedCreate --sort-by=.lastTimestamp
# What standard does the namespace enforce?
kubectl get ns <ns> -o jsonpath='{.metadata.labels}' | tr ',' '\n' | grep pod-security
# Which webhooks/policies are in play?
kubectl get validatingwebhookconfigurations
kubectl get clusterpolicies # Kyverno
kubectl get constraints # Gatekeeper
# Safe test namespace with warnings on
kubectl label ns scratch pod-security.kubernetes.io/warn=restricted --overwrite
Conclusion
admission webhook ... denied the request / violates PodSecurity means a security policy blocked the workload before it was created — the guardrail doing its job. Read the denial as a checklist:
- Missing
restrictedcontrols:runAsNonRoot,allowPrivilegeEscalation=false,drop: ["ALL"], seccomp. - A privileged container or host namespace/hostPath the standard forbids.
- A custom Kyverno/Gatekeeper policy the spec doesn’t satisfy.
- A namespace enforce label stricter than the manifest.
- A blocked added capability like
NET_ADMIN/SYS_ADMIN. - A
failurePolicy: Failwebhook that is actually unavailable.
Read the full message, identify the engine, fix the pod template’s securityContext to comply, and test against the target standard in a scratch namespace — harden the workload rather than exempt it.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.