Problem – Admission Controller Rejects GPT‑4 Canary Pods
During a staged rollout of a new GPT‑4 inference service, the canary pods never reach the Running state. The Kubernetes API server returns a 403 error from the pod-security-admission webhook and a custom model‑policy webhook. Typical log excerpts look like:
Error from server (Forbidden): admission webhook "pod-security-admission" denied the request:
securityContext.runAsUser is required
metadata.labels: Invalid value: "{app: gpt4-canary}": must match label selector 'app.kubernetes.io/component=gpt4'
admission webhook "custom-model-policy" denied the request: securityContext.allowPrivilegeEscalation must be false
The failure blocks the canary deployment, causing a full rollout pause and risking SLA violations for the AI SaaS platform.
Root Cause – Missing Required securityContext and Label Constraints
Two independent admission controls enforce the Pod Security Standards (PSS) “restricted” profile and a custom model policy:
- PodSecurityAdmission (PSA) webhook – Requires
runAsNonRoot: true,runAsUser,runAsGroup, andreadOnlyRootFilesystem: trueinsecurityContext. It also enforces the label selectorapp.kubernetes.io/component=gpt4for all GPT‑4 workloads. - Custom model‑policy webhook – Checks that
allowPrivilegeEscalation: falseis explicitly set and that the pod carries the mandatory component label.
In the canary manifest the securityContext fields were omitted to keep the Helm chart minimal, and the required label was missing because the chart used a generic app: gpt4 label. This violates both the official PSS documentation and the custom policy introduced after a recent security hardening sprint (see the production incident on GKE where runAsUser and runAsGroup were omitted).
Debug – Investigation Steps
1. Capture the Admission Rejection
$ kubectl describe pod gpt4-canary-5f9d8c7b9c-abcde
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Failed 2s pod-security-admission securityContext.runAsUser is required
Warning Failed 2s custom-model-policy securityContext.allowPrivilegeEscalation must be false
2. Verify PSA Policy Mode
$ kubectl get ns gpt4-canary -o jsonpath='{.metadata.labels.pod-security.kubernetes.io/enforce}'
restricted
3. Inspect the Helm values used for the canary
$ helm get values gpt4-inference --revision 12 --output yaml
...
securityContext: {}
labels:
app: gpt4
tier: canary
4. Review the custom webhook configuration
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: custom-model-policy
webhooks:
- name: model-policy.example.com
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
clientConfig:
service:
name: model-policy-webhook
namespace: kube-system
caBundle:
admissionReviewVersions: ["v1"]
sideEffects: None
failurePolicy: Fail
5. Reproduce the failure with a minimal pod
apiVersion: v1
kind: Pod
metadata:
name: test-gpt4
labels:
app: gpt4
spec:
containers:
- name: inference
image: openai/gpt4-inference:latest
Running kubectl apply -f test.yaml yields the same admission errors, confirming the root cause.
Solution – Add Required Security Context and Labels
The fix consists of two parts: (1) enrich the pod securityContext to satisfy the “restricted” PSS, and (2) ensure the mandatory component label is present. Below are the before/after manifests and the Helm value overrides.
Before – Faulty Canary Manifest (excerpt)
apiVersion: apps/v1
kind: Deployment
metadata:
name: gpt4-canary
spec:
replicas: 2
selector:
matchLabels:
app: gpt4
template:
metadata:
labels:
app: gpt4
tier: canary
spec:
containers:
- name: inference
image: openai/gpt4-inference:{{ .Values.imageTag }}
resources:
limits:
cpu: "4"
memory: "16Gi"
# securityContext omitted
After – Corrected Canary Manifest (excerpt)
apiVersion: apps/v1
kind: Deployment
metadata:
name: gpt4-canary
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: gpt4
app.kubernetes.io/component: gpt4
tier: canary
template:
metadata:
labels:
app.kubernetes.io/name: gpt4
app.kubernetes.io/component: gpt4
tier: canary
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
containers:
- name: inference
image: openai/gpt4-inference:{{ .Values.imageTag }}
resources:
limits:
cpu: "4"
memory: "16Gi"
securityContext:
capabilities:
drop: ["ALL"]
Helm Value Override (values.yaml)
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
labels:
app.kubernetes.io/name: gpt4
app.kubernetes.io/component: gpt4
tier: canary
Applying the updated chart (helm upgrade --install gpt4-inference ./chart -f values.yaml) creates pods that pass both admission controllers.
Verify – Confirming Successful Canary Rollout
- Pod status – All canary pods reach
Runningwithout admission errors. - Admission logs – No entries from
pod-security-admissionorcustom-model-policyfor the new pods. - Metrics – Inference latency and request count appear in Prometheus under
gpt4_canary_*labels.
$ kubectl get pods -l app.kubernetes.io/component=gpt4 -o wide
NAME READY STATUS RESTARTS AGE IP NODE
gpt4-canary-5f9d8c7b9c-abcde 1/1 Running 0 2m 10.12.3.45 gke-node-1
gpt4-canary-5f9d8c7b9c-fghij 1/1 Running 0 2m 10.12.3.46 gke-node-2
Prevent – Operational Guardrails
| Preventive Action | Implementation |
|---|---|
| Enforce Helm linting for securityContext | Add a helm lint rule or a pre-commit hook that checks for runAsUser, runAsGroup, and readOnlyRootFilesystem fields. |
| Label validation CI job | Run kubectl apply --dry-run=client -f manifests/ and grep for missing app.kubernetes.io/component=gpt4 label. |
| PodSecurityAdmission audit mode | Set audit mode for the restricted policy in non‑production clusters to surface violations before they block deployments. |
| Custom webhook unit tests | Include integration tests that submit a minimal pod manifest and assert a 200 response from the webhook. |
Related Topic Hub: LLM Systems Troubleshooting Hub
FAQ
- Why does the pod pass locally but fail in the canary namespace?
The canary namespace is labeled withpod-security.kubernetes.io/enforce=restricted, which activates stricter PSA checks than the default namespace. - Can I disable the custom model‑policy webhook for canary testing?
You can set the webhook’sfailurePolicytoIgnorein a test cluster, but in production it is recommended to fix the manifest rather than bypass security checks. - Do I need to set
securityContext.runAsNonRootif I already setrunAsUser?
Yes. The “restricted” profile explicitly requiresrunAsNonRoot: truein addition to a non‑zerorunAsUser. - What label selector should I use for future model versions?
Follow the conventionapp.kubernetes.io/name=gpt4andapp.kubernetes.io/component=gpt4. If you introduce a new model family, change thecomponentvalue accordingly (e.g.,gpt4‑v2). - Is
readOnlyRootFilesystemmandatory for all containers?
Under the “restricted” PSS it is required for every container. If a container needs write access, use anemptyDirvolume and mount it at the required path.