Control admission
Syself Autopilot ships built-in admission protection that prevents a broken webhook from locking your cluster, and it lets you write your own hard gates that cannot be taken offline. Admission control is the step where the Kubernetes API server checks or modifies an object (such as a Pod or Deployment) before saving it, and can reject it, change it, or both. With it you enforce cluster-wide rules on every object before it is saved: "no privileged pods," "images must be signed," or "every Deployment needs a cost label." Beyond the built-in protection, one further platform policy rejects network-policy rules the platform cannot enforce correctly.
How a broken webhook can lock your cluster#
An admission webhook is a pod that the API server calls on every matching request. A ValidatingWebhookConfiguration is a Kubernetes object that connects an external service to the admission process. If you register one with failurePolicy: Fail and that service becomes slow or unreachable, the API server rejects every request it cannot check.
That includes requests from the platform components that manage your cluster, so the control plane itself is locked out.
The problem is not a permissions issue. RBAC (Role-Based Access Control) decides who can do what in the cluster. system:masters is its most privileged group and skips RBAC checks. But even system:masters does not skip admission webhooks. A webhook with failurePolicy: Fail blocks everyone, including cluster admins. A single broken webhook can make the whole cluster unusable.
How the platform's admission protection works#
The platform's admission protection uses ValidatingAdmissionPolicies (VAPs). A VAP is written in CEL (Common Expression Language, a small rule language built into Kubernetes) and runs inside the API server itself. Because it runs inside the API server, there is no pod to crash and no service to overload. VAPs cannot be taken offline.
Restrict tenant webhooks. The policy syself-restrict-tenant-webhooks enforces these rules on every tenant ValidatingWebhookConfiguration or MutatingWebhookConfiguration:
- Webhooks may not target the admission-registration API (
admissionregistration.k8s.io) or use a wildcardapiGroups: ["*"]. This stops a webhook from disabling the admission protection. - Webhooks may not target the authentication or authorization APIs (
authentication.k8s.io,authorization.k8s.io). This stops a webhook from hijacking auth and guaranteessystem:masterscan always authenticate. - Webhooks that touch roles, role bindings, or service accounts must be namespace-scoped: they may not target cluster roles or cluster role bindings, and may not use resource wildcards. This keeps a tenant webhook from reaching RBAC objects outside its own namespace.
These rules do not require failurePolicy: Ignore. A tenant webhook can use failurePolicy: Fail, as long as it stays out of the APIs above. The goal is narrower: guarantee that a cluster admin can always authenticate and delete a broken webhook, not force every webhook into best-effort mode.
Protect platform policies. The policy syself-protect-platform-policies prevents tenants from creating, modifying, or deleting any admission policy whose name starts with syself-. This protects all platform admission policies from being modified or removed.
Restrict network-policy rules that need a proxy. The policy syself-restrict-l7-proxy-policies is the one built-in policy that is not about webhooks. It rejects the CiliumNetworkPolicy and CiliumClusterwideNetworkPolicy rules that cannot be enforced correctly on this platform, because each of them routes matched traffic through a userspace proxy on the node instead of letting the kernel handle it directly.
Its parts do not all mean the same thing:
| Rule | Where | Status |
|---|---|---|
Application-layer rules: rules.http, rules.kafka, rules.l7proto, rules.l7, and the listener, serverNames, terminatingTLS and originatingTLS fields next to them | CiliumClusterwideNetworkPolicy | Rejected permanently |
| The same rules | CiliumNetworkPolicy (namespaced) | Rejected for now |
DNS rules: toPorts[].rules.dns, and toFQDNs, which needs one | Both kinds | Rejected for now |
The permanent one is a deliberate design choice, not a bug we are working around: a cluster-wide policy applies to every namespace at once, so one application-layer rule would put every matching connection in the cluster through request-level parsing, including workloads whose owners never saw the policy. If application-layer rules become available here, they will be available in a namespaced policy only.
The other two are temporary and lift on their own schedules. Syself re-evaluates these gated capabilities with each new Kubernetes minor release. Layer 3 and Layer 4 rules (workload identity, IP ranges, entities, and ports) are not affected by any part of this policy and are enforced normally in both kinds. See Segment with network policies for what to write instead while the temporary parts are in force.
These policies all use validationActions: [Deny]. When you apply an object that violates these rules, the API server rejects the apply with a Forbidden error naming the policy. The object is never created.
Note
If kubectl apply fails with a syself-restrict-tenant-webhooks error, remove any rule that targets admissionregistration.k8s.io, authentication.k8s.io, or authorization.k8s.io, or that uses a wildcard apiGroup. Also make sure any webhook matching roles, role bindings, or service accounts is namespace-scoped: it must not match cluster roles or cluster role bindings, and must not use resource wildcards.
Who is exempt#
The webhook policies (syself-restrict-tenant-webhooks and syself-protect-platform-policies) exempt the system:masters group and the platform's internal cluster-admin group; for those, platform components and the cluster admin identity are unrestricted. Everyone else is subject to the rules. syself-restrict-l7-proxy-policies has no exemption: it applies to every caller, including cluster admins and platform components.
This creates a security requirement: tenants must never be granted system:masters or the platform's internal cluster-admin role on a workload cluster. If they are, they can bypass those webhook policies. Keep tenants off those groups using RBAC. See Manage access and tenancy .
Upgrade safety#
The platform deploys these admission policies as part of cluster setup and upgrades. If a policy ever fails to deploy, the cluster keeps working.
Running your own admission policies#
You can enforce your own policies in two ways. The choice determines how strongly they block.
Use ValidatingAdmissionPolicy for hard gates#
A native VAP is a CEL (Common Expression Language: a compact rule language built into Kubernetes) policy that runs inside the API server. It has no backend pod to go down, so it does not carry the reliability trade-off that a webhook-based tool does. A native VAP can hard-deny (fail closed) and cannot be taken offline.
For rules that must block without exception, such as "reject privileged pods, always," write a native VAP. Do not name it syself-*; that prefix is reserved for platform policies.
Webhook-based tools are a trade-off#
Tools like Kyverno and OPA Gatekeeper use a ValidatingWebhookConfiguration to validate resources. The platform does not force these webhooks to failurePolicy: Ignore; you can set failurePolicy: Fail as long as the webhook stays out of the admission-registration, authentication/authorization, and cluster-scoped RBAC APIs described above. Those restrictions are what keep a cluster admin able to authenticate and delete a broken webhook.
That still leaves a trade-off for your own workloads. A webhook-based tool is only as reliable as its backend pod. With failurePolicy: Fail, if the Kyverno pod goes down, requests that match its rules are blocked. Admin recovery still works, but your own workloads are stuck. With failurePolicy: Ignore, a Kyverno outage lets those requests through instead of blocking them.
Practical guidance:
- Use Kyverno mutate and generate rules freely. Those do not gate admission the same way.
- For rules that must hard-block without depending on a pod staying up, write a native VAP in CEL instead of a Kyverno validating policy.
- If you want validation that never blocks your workloads during a Kyverno outage, run it with
failurePolicy: Ignoreand keep Kyverno highly available so that path rarely triggers.
See Use Kyverno policies for Kyverno-specific guidance.
What the platform already enforces#
Beyond the admission guardrails, the API server runs these admission plugins by default:
NodeRestriction: a node agent can only modify its own node and its own pods. It cannot touch other nodes or pods on other nodes.
EventRateLimit: caps how many events per second the API server records. This stops a misbehaving workload from flooding the API server with events.
Related#
Enforce Pod Security Standards
Roll out Pod Security Standards on a Kubernetes namespace without breaking running workloads: audit first, then enforce the baseline or restricted level.
Use Kyverno policies
Install Kyverno on a Syself workload cluster, configure failurePolicy correctly, and pick the right rule type for mutations, generation, validation, and image signing.