ValidatingAdmissionPolicy lets the Kubernetes API server evaluate Common Expression Language rules without calling an external webhook. A policy declares the validation expressions. A binding decides which requests use the policy and whether violations are denied, audited or merely warned. Match conditions narrow that scope further. They look like a convenience, but a false result skips the policy.

Kubernetes documentation is explicit that if any match condition evaluates to false, the API server skips the policy regardless of other errors. That behavior makes a careless expression a security configuration change. A condition intended to select namespaces with a particular label may silently exclude every namespace after a label migration. A condition that expects a parameter or request attribute may evaluate incorrectly during a version upgrade, and a policy that reports a warning does not necessarily block the object.

Treat the policy, binding and parameters as one unit. Review matchResources and matchConditions together. Confirm that the namespaces, resource kinds, operations and users selected are the ones the control owner intended. When the binding references a parameter resource, test what happens when the parameter is missing, changed or inaccessible. Also check who can update the policy, binding and parameter. A team that can edit a parameter may be able to turn a deny into an audit rule without touching the CEL expression.

Use audit and warning actions before enforcement, but do not let a clean audit report substitute for a negative test. Build requests that should be denied, requests that should be allowed, and requests just outside the policy's scope. Apply them with dry-run where supported and inspect the admission result. Then test the same cases after a cluster upgrade and after any change to labels, namespaces or parameter objects.

CEL expressions should fail closed when the request does not contain the fields needed to make a decision. Avoid expressions that accidentally compare an absent value to a permissive default. Keep messages specific enough to explain the rejected condition without echoing secrets. Bound expression cost and object size because admission runs in the API server and affects the control plane, not only the target workload.

The control plane needs an ownership model. An application team may own the content of a policy while the platform team owns the binding and the parameter resource. If both teams can change both layers, the separation is cosmetic. Store the intended scope in version control, review changes with the same process used for RBAC, and alert on policy or binding changes that disable a security control.

There is no universal expression that makes an admission policy safe. The useful pattern is explicit scope, tested deny cases, a named owner, and a response plan for parameter or label drift. A policy that exists in the cluster is not necessarily a policy that evaluated against the request that mattered.

References