Admission Controllers in Kubernetes

Admission Controllers in Kubernetes

Every object that enters your cluster passes through a final checkpoint that can change it, approve it, or turn it away. This guide explains how that checkpoint works, from the built-in plugins to webhooks, CEL policies, and the habits that keep it reliable in production.

Imagine a large office building with a front desk. You have already shown your ID badge, and the guard has checked that your badge is allowed to enter the building. You might think that is enough. But before you walk to the elevator, a second person at the desk looks at the package you are carrying. They might stick a visitor label on it, they might ask you to open it, or they might say, “Sorry, nothing like that is allowed upstairs.” That second person is the admission controller of the building.

Kubernetes works in a very similar way. Proving who you are and having permission to act are not the whole story. Once a request to create or change something passes those two checks, it still has to pass through admission control, where the content of the request is examined and sometimes rewritten. This is where clusters enforce company rules, add default settings, inject helper containers, and stop risky workloads before they ever start.

In this guide we move step by step. We start with the basic idea, follow a request through the API server, learn the two kinds of admission, tour the built-in plugins, and then go deeper into webhooks, the newer policy objects written in CEL, and the operational lessons that separate a smooth cluster from a fragile one. No earlier knowledge is assumed, and every new term is explained when it first appears.

1What Is an Admission Controller?

An admission controller is a piece of code inside the Kubernetes API server that looks at a request after it has been authorized and before the object is saved.

The Short Definition

Kubernetes keeps all of its state, such as Pods, Services, Deployments, and Secrets, in a database called etcd. The only front door to that database is the API server. Whenever you run a command, apply a manifest, or a tool like a CI pipeline talks to your cluster, the request arrives at the API server. An admission controller is a plugin in that front door which gets a chance to inspect, modify, or reject the request before it is written to etcd.

Two words matter here: “inspect” and “modify”. Some admission controllers only look and then say yes or no. Others actually change the object, for example by filling in a missing default value. Both kinds exist, and we will separate them clearly in a later chapter.

Simple Analogy

Think of a school reception office. The receptionist already knows you are a registered parent (authentication) and that parents may collect students (authorization). Still, before handing over a child, they check the paperwork: Is today a valid day? Is the pickup form complete? Is there a note from the teacher? They may even stamp the form with the date. That final paperwork check, with the power to stamp or refuse, is admission control.

Why Do We Need It?

Authentication answers “who are you?” and authorization answers “are you allowed to do this kind of action?” Neither one looks deeply at the thing you are asking for. Authorization might say “Maya can create Pods in the payments namespace,” but it cannot say “Maya may create Pods only if they do not run as the root user and only if they pull images from our company registry.” Rules about the content of an object need a different layer, and admission control is that layer.

Without it, every team would need to remember every rule by heart, and one forgotten setting could expose the whole cluster. With it, the rules live in one central place and are applied to everyone automatically, whether the request comes from a human, a script, or another controller.

4
Request types it watches: create, update, delete, and connect
0
Read requests it touches: get, list, and watch skip admission
2
Phases: first change the request, then validate it

What It Does Not Do

It is just as important to know the limits. Admission controllers do not run on read requests, so they cannot hide or filter what people see. They also do not watch objects that already exist in the cluster; they only see requests as those requests arrive. If you create a bad object before a rule exists, the rule will not remove it later. It will only react the next time someone tries to update that object. Keep this in mind, because it explains many surprises in real clusters.

The “connect” operation deserves a short note. It covers actions like opening a shell inside a running container or forwarding a port. These are not changes to stored objects, but they are sensitive, so admission can still examine them.

i
Remember This

Authorization decides whether you may perform an action. Admission decides whether the specific object you are submitting is acceptable. Two different questions, two different layers.

2Where Admission Fits in the Request Lifecycle

To understand admission, it helps to follow a single request from the moment it leaves your laptop until it is stored.

The Journey of One Request

Suppose you ask Kubernetes to create a Deployment. Your request is sent over a secure connection to the API server. From that moment it passes through a fixed series of stages, always in the same order. The diagram below shows the full path.

flowchart LR
    A["Client request"] --> B["Authentication"]
    B --> C["Authorization"]
    C --> D["Mutating admission"]
    D --> E["Schema validation"]
    E --> F["Validating admission"]
    F --> G["Saved to etcd"]
    B -. "rejected" .-> X["Error returned"]
    C -. "rejected" .-> X
    D -. "rejected" .-> X
    E -. "rejected" .-> X
    F -. "rejected" .-> X
        
FIG 1 — The path of a request through the API server
1

Authentication

The API server works out who is calling, using a certificate, a token, or an identity provider. If it cannot identify the caller, the request stops here.

2

Authorization

The server checks whether this caller may perform this action on this kind of resource. This is usually decided by role-based access control, often shortened to RBAC.

3

Mutating Admission

Plugins and webhooks that are allowed to change the object run one after another. They might add labels, set defaults, or attach a sidecar container.

4

Object Schema Validation

The server checks that the final object, after all the changes, still matches the official shape of that resource type. Unknown fields or wrong value types are rejected.

5

Validating Admission

Plugins and webhooks that may only approve or reject now look at the final object. They cannot change it. If any one of them says no, the whole request fails.

6

Persistence

Only after every earlier stage has agreed is the object written to etcd, and only then can controllers in the cluster begin acting on it.

Why the Order Matters

The order is not an accident. Changing the object comes before the final validation so that the validators judge the object that will actually be stored, not an early draft. If validation came first, a mutating step could silently break a rule that had just been checked. By putting every mutation before every validation, Kubernetes gives validators the last word.

Another consequence is that rejection is final and early. If any admission step says no, the request fails immediately and the user receives an error message explaining why. Nothing is stored, and no later stage runs.

!
Common Misconception

People often assume admission runs when a Pod actually starts on a node. It does not. Admission happens at the API server, long before any scheduling or container start. A rejected Pod never exists at all.

3Mutating vs Validating Admission

Admission controllers come in two roles, and understanding the difference is the single most useful idea in this whole topic.

Mutating Controllers

A mutating controller is allowed to modify the incoming object. Typical jobs include adding a default storage class to a volume claim, setting a default service account on a Pod, attaching standard labels, or injecting an extra container next to your application container. Mutation is about convenience and consistency: the user does not have to remember each detail because the cluster fills it in.

Because one mutation can affect the next, mutating controllers run one after another in a defined order. Each one sees the result of the previous one.

Validating Controllers

A validating controller can only say yes or no. It receives the final version of the object and decides whether it follows the rules. Since it cannot change anything, there is no risk of one validator interfering with another, so validating controllers can be evaluated independently of each other, and the request is accepted only if every single one approves.

Simple Analogy

Picture a restaurant kitchen. The prep cooks are mutating controllers: they trim, season, and plate the dish, and each cook works on what the previous cook handed over. The head chef at the pass is the validating controller: tasting the final plate and saying either “send it out” or “back to the kitchen.” The chef never adds salt; the chef only approves or refuses.

AspectMutatingValidating
Can change the objectYesNo
Can reject the requestYesYes
When it runsBefore schema validationAfter schema validation
Execution styleOne after another, in orderIndependent checks, all must pass
Sees the final objectNo, later mutations may followYes
Typical purposeDefaults, injection, labelsPolicy, security, compliance

Some Plugins Do Both

Several built-in plugins are both mutating and validating. They simply take part in both phases: first they may adjust the object, and later they check it. The Kubernetes documentation marks which plugins act in which phase, so it is worth checking when you rely on a particular one.

i
Design Tip

Whenever you can, use a validating rule instead of a mutating one. Silent changes can surprise users, while a clear rejection with a helpful message teaches them what to fix. Reserve mutation for cases where a sensible default or an automatic injection genuinely helps.

4The Built-in Admission Controllers

Kubernetes ships with a long list of admission plugins that are compiled directly into the API server. Many are switched on by default, and you probably rely on several of them without knowing.

How They Are Switched On and Off

The API server has settings that enable additional plugins and disable default ones. A cluster administrator who controls the control plane can tune these. Be aware that on most managed Kubernetes services, the provider decides the plugin list, and you may not be allowed to change it. This is one reason the webhook and policy approaches in later chapters are so popular: they work on any cluster without touching the API server settings.

A Tour of Important Plugins

The list below is not complete, but it covers the plugins most engineers meet in daily work. Each card explains what the plugin is for in plain words.

Namespaces

NamespaceLifecycle

Blocks new objects from being created inside a namespace that is being deleted, and protects the core system namespaces from removal.

Defaults

LimitRanger

Applies default CPU and memory requests and limits, and rejects Pods that fall outside the minimum and maximum set for the namespace.

Quotas

ResourceQuota

Enforces the total amount of resources or objects a namespace may use, so one team cannot consume the entire cluster.

Identity

ServiceAccount

Automatically attaches a service account to Pods that do not name one, so every Pod has an identity inside the cluster.

Storage

DefaultStorageClass

Assigns the default storage class to a volume claim that does not request one, so storage requests work without extra detail.

Nodes

NodeRestriction

Limits what each node agent may modify, so a compromised node can only touch its own Node object and the Pods assigned to it.

Security

PodSecurity

Applies the Pod Security Standards at the namespace level, deciding which Pod settings are acceptable. A full chapter covers it below.

Scheduling

Priority

Resolves a named priority class into a numeric priority on the Pod, and rejects names that do not exist.

Two Plugins That Open the Door to Extension

Among the built-in plugins, three are special because they let you add your own logic without rebuilding the API server. They are the mutating webhook plugin, the validating webhook plugin, and the validating admission policy plugin. They act like sockets: the built-in code is fixed, but what plugs into it is yours to define. Chapters 5 through 9 are about these.

!
Heads Up

Some plugins, such as ones that force images to always be pulled or that restrict scheduling by namespace, are not on by default. If a behavior you expect is missing, check whether the plugin is actually enabled on your cluster rather than assuming it is.

5Dynamic Admission: Webhooks

Built-in plugins cover common needs, but every company has its own rules. Admission webhooks let you run those rules in a separate service of your own.

What Is a Webhook?

A webhook is simply a web address that gets called when something happens. In this case, “something happens” means a matching request has reached the admission stage. The API server pauses the request, sends a description of it to your service over a secure connection, waits for your answer, and then continues or stops depending on what you say.

Your service can be anything that speaks the right format: a small program you wrote, a full policy engine, or a vendor product. It usually runs inside the cluster as an ordinary Deployment with a Service in front of it, though it can also live outside the cluster at a public address.

sequenceDiagram
    participant U as User
    participant A as API Server
    participant M as Mutating Webhook
    participant V as Validating Webhook
    participant E as etcd
    U->>A: Create Pod request
    A->>M: Admission review with the object
    M-->>A: Allowed, plus a list of changes
    A->>A: Apply changes and check schema
    A->>V: Admission review with final object
    V-->>A: Allowed or denied with a reason
    A->>E: Store the object
    A-->>U: Success response
        
FIG 2 — How the API server consults webhooks during one request

Registering a Webhook

You do not tell the API server about your service in a command-line flag. Instead, you create a Kubernetes object that describes it. There are two such objects: one for mutating webhooks and one for validating webhooks. Each object lists which requests to send (by resource type, operation, and optionally namespace or labels), where to send them, and how to behave if something goes wrong. We study those settings in Chapter 7.

Simple Analogy

Registering a webhook is like putting a note on the building’s front desk: “For any package addressed to the third floor, call extension 214 before letting it through.” The desk staff do not need to know why; they just follow the note, wait for the answer on the phone, and act on it.

Security of the Conversation

The API server only talks to webhooks over encrypted connections. Your service needs a valid certificate, and the registration object carries the certificate authority that the API server should trust when it connects. If that certificate expires or the trust information goes stale, the API server can no longer reach your service. Depending on settings, the result is either blocked requests or skipped checks, and both are painful. Many teams automate certificate renewal for exactly this reason.

Use Case: Sidecar Injection

Service meshes and secret-delivery tools use mutating webhooks to add an extra container to every new Pod in selected namespaces. Developers write a plain Pod, and the webhook quietly adds the proxy or agent that makes it part of the mesh.

Use Case: Enforcing Company Rules

A validating webhook can reject any workload that pulls an image from an untrusted registry, lacks an owner label, or asks for more memory than the team budget allows. The error message tells the developer exactly which rule was broken.

6Anatomy of an Admission Request and Response

Webhooks and the API server talk using a small, well-defined message called an AdmissionReview. Knowing what is inside it makes debugging far easier.

The Question the API Server Asks

When the API server calls your webhook, it sends one message called an AdmissionReview. Inside the request part of this message you will find a set of useful facts. Think of it as a form that the API server fills in before handing it to your service.

Field

Unique ID

A unique identifier for this exact request. Your answer must repeat it so the API server can match reply to question.

Field

Kind and Resource

What type of object this is, such as a Pod or a Deployment, and which API group and version it belongs to.

Field

Operation

Whether the user is creating, updating, deleting, or connecting. Many rules only care about one of these.

Field

User Information

The name, groups, and extra attributes of the caller, which lets you apply different rules to people and to automated systems.

Field

New Object

The full object as the user submitted it, including any changes made by earlier mutating steps.

Field

Old Object

For updates and deletes, the version currently stored. Comparing old and new lets you block risky changes, such as editing an immutable setting.

Field

Namespace and Name

Where the object lives and what it is called. For creates with generated names, the name may be empty at this point.

Field

Dry Run Flag

Tells you the request is only a rehearsal and must not cause real-world effects outside the cluster.

The Answer Your Webhook Gives

Your service replies with a response that repeats the unique ID and states whether the request is allowed. A denial can include a status with a human-readable message and a code, and that message is shown to the user, so write it clearly. A good denial says which rule was broken and how to fix it, not just “forbidden.”

A mutating webhook can also return a list of changes, written in a standard format called JSON Patch. It is a precise recipe, such as “add this label” or “replace that value,” which the API server applies to the object. A response may also carry warnings: short messages shown to the user even though the request succeeded. Warnings are a gentle way to announce that a rule will soon become strict. There are also audit annotations, small notes added to the audit log entry for the request, which help security teams trace decisions later.

i
Practical Tip

Use warnings to roll out new rules gently. First warn for a few weeks so teams can fix their manifests, then switch the same rule to deny. This avoids the angry surprise of suddenly blocked deployments.

Versions of the Message

The message format is versioned, and the registration object lists which versions your service understands. The API server picks one that both sides support. Always support the current stable version, because older formats are removed in newer clusters.

7Webhook Configuration Settings That Matter

A webhook is only as safe as its registration. A handful of settings decide whether your cluster stays healthy when something goes wrong.

Choosing What Gets Sent

Not every request needs to reach your webhook. Sending everything wastes time and increases risk. The registration lets you narrow things down in several ways. Rules pick the API groups, resource types, and operations. A namespace selector includes or excludes whole namespaces by their labels. An object selector filters by the labels on the object itself. Newer clusters also support match conditions, small expressions written in CEL, a safe expression language we meet in the next chapter, which let the API server skip the call entirely when a condition is not met. Filtering before the network call is the cheapest optimization available.

Failure Policy: The Most Important Choice

What should happen if your webhook is down, slow, or broken? The failure policy answers that question, and it has two options.

Fail Closed

  • Requests are rejected when the webhook cannot answer
  • No rule can be bypassed during an outage
  • Right choice for critical security controls
  • Predictable and easy to reason about

Fail Open

  • Requests are allowed when the webhook cannot answer
  • Cluster keeps working during webhook outages
  • Rules may be silently skipped in that window
  • Suited to helpful but non-critical mutations

There is no universal answer. A webhook that blocks privileged containers should usually fail closed, because skipping it would defeat its purpose. A webhook that adds optional labels can usually fail open. What matters is that you make the choice on purpose, write it down, and test what really happens when the service disappears.

Timeouts, Side Effects, and Re-invocation

1

Timeout

The registration sets how long the API server will wait, within a small allowed range of seconds. Every admission call adds to user-visible latency, so shorter is better. Aim for answers in milliseconds.

2

Side Effects Declaration

You must state whether your webhook changes anything outside the cluster, such as calling an external system. Dry-run requests go through admission too, so a webhook with hidden side effects could do real damage during a rehearsal. Declare honestly, and skip side effects on dry runs.

3

Match Policy

A resource can be reachable through more than one API version. The match policy decides whether your rule also catches equivalent versions, so that a request cannot dodge the rule by using a different version name.

4

Reinvocation Policy

Because mutating steps run in sequence, a later webhook may change something an earlier webhook cared about. The reinvocation policy lets a mutating webhook be called a second time if later steps altered the object. Your logic must therefore be safe to run more than once with the same result.

ANTI-PATTERN-01 Avoid
Problem

A webhook is registered to fail closed and to intercept every Pod in every namespace, including the namespace where the webhook service itself runs.

Why It’s Harmful

If the webhook Pods ever restart, the API server asks the webhook for permission to create the very Pods that would answer the question. The answer never comes, so the service can never return. This deadlock can also block critical system components.

Correct Approach

Exclude the webhook’s own namespace and the core system namespaces using a namespace selector, run several replicas spread across nodes, and keep the failure policy decision deliberate for each webhook.

8ValidatingAdmissionPolicy and CEL

Running a separate service just to say “no” to a few bad configurations is a lot of machinery. Kubernetes now lets you write such rules as plain objects, evaluated inside the API server itself.

The Problem with Webhooks

Webhooks are powerful, but they come with costs. You must build and maintain a service, keep certificates fresh, make it highly available, and accept the extra network hop on every matching request. For simple rules, this is like hiring a security company to check whether a form has a signature.

What CEL Is

CEL, short for Common Expression Language, is a small, safe language for writing conditions. It cannot loop forever, cannot access files, and cannot call the network. Because it is so limited, the API server can run it directly with predictable cost. A CEL rule looks at the incoming object and returns true or false. For example, a rule can express “every container must have a memory limit” or “replica count must not exceed ten.”

The Two Objects

The feature uses two cooperating objects. The first is the policy, which describes which resources it applies to, optional variables, and one or more validation rules with their messages. The second is the binding, which connects a policy to a scope, such as particular namespaces, and decides what happens on a violation. Splitting the two means one policy can be reused with different scopes and different strictness.

Action

Deny

The request is rejected, and the user sees your message. This is the enforcement mode.

Action

Warn

The request succeeds, but the user receives a warning message. Ideal for announcing upcoming rules.

Action

Audit

The request succeeds, and the violation is recorded in the audit log for later review by the security team.

Parameters Make Policies Reusable

A policy can point to a separate parameter object, for example a small configuration holding the maximum allowed replica count. Different bindings can supply different parameter objects, so the same rule can be strict in production and relaxed in development without copying the policy.

Simple Analogy

A policy is like a speed limit sign design: “vehicles must not exceed the posted number.” The binding is where you actually put the sign, and the parameter is the number written on it. The same sign design works on a quiet village road with one number and on a motorway with another.

Advantages

  • No extra service to run, patch, or scale
  • Evaluated inside the API server with low latency
  • No certificate management or network failure modes
  • Rules are declarative and easy to review in version control
  • Warn and audit modes make safe rollouts simple

Disadvantages / Trade-offs

  • Validation only; it cannot call external systems
  • Logic is limited to what CEL can express
  • Complex rules can become hard to read
  • Needs a cluster version that supports the feature
i
Rule of Thumb

Start with a CEL policy for any rule that only needs to look at the object itself. Reach for a webhook only when you need outside data, such as a database lookup or a signature check on an image.

9Mutating with Policies Instead of Webhooks

The same idea that replaced simple validating webhooks is being extended to mutation, so common defaults can also be declared without running your own service.

The Idea

A mutating admission policy follows the same model as its validating cousin. You describe the resources it applies to and express the change you want using CEL, and the API server applies it. Typical examples include adding a default label, setting a safe default value, or adding a standard annotation. As there is no webhook service, there is no network call, no certificate, and no outage risk from a missing service.

!
Check Your Version

This capability is newer than validating policies and has been maturing across recent Kubernetes releases. Whether it is available, and whether it is on by default, depends on your cluster version and its feature settings. Always read the release notes and the official documentation for your version before depending on it.

When Webhooks Are Still the Better Tool

Policies are intentionally limited. If your mutation needs complex logic, needs to generate a lot of content such as a full sidecar definition based on external templates, or needs to talk to another system, a webhook remains the right answer. Think of policies as the everyday tool and webhooks as the specialist tool.

NeedBest FitReason
Simple yes or no rule on the objectValidating policy with CELFast, no service to run
Add a label or default valueMutating policy, where availableDeclarative and low risk
Inject a sidecar containerMutating webhookNeeds rich, template-based logic
Check against an external databaseValidating webhookCEL cannot call outside systems
Enforce rules across many clustersPolicy engineCentral management and reporting

10Policy Engines: Kyverno and OPA Gatekeeper

Writing and maintaining raw webhooks for every rule does not scale. Policy engines package the webhook, the certificates, and a friendly rule language into a ready-made product.

What a Policy Engine Does

A policy engine is a program you install in the cluster that registers its own admission webhooks. You then write rules in the engine’s own format, and the engine decides how each incoming request should be handled. It also usually adds extras: reports on existing objects that already violate a rule, tools to test policies before release, and exception handling for teams that need a rare bypass.

Engine

Kyverno

Designed specifically for Kubernetes. Policies are written as Kubernetes resources using familiar structure, and it can validate, mutate, and even generate new objects. Many teams find it the gentlest to learn.

Engine

OPA Gatekeeper

Brings the general-purpose Open Policy Agent to Kubernetes. Rules are written in a dedicated policy language and organized as reusable templates plus constraints that apply them. Very flexible, with a steeper learning curve.

How to Choose

If your team wants to stay inside Kubernetes-style configuration and values quick adoption, an engine built around Kubernetes resources is attractive. If your organization already uses the same policy language for other systems such as pipelines or cloud access, a general-purpose engine gives you one language everywhere. Many engines also support the native policy objects from the previous chapters, so the choice is not as final as it once was.

!
Do Not Overlap Blindly

Running two engines, or an engine plus several custom webhooks, multiplies the number of network calls on every request and makes it hard to tell which component rejected something. Decide who owns which category of rule and keep it simple.

11Pod Security Admission

One built-in admission plugin deserves its own chapter because almost every cluster uses it: the one that stops dangerous Pods.

From PodSecurityPolicy to Pod Security Admission

Older clusters used an object called PodSecurityPolicy to control risky Pod settings. It was confusing to use and was removed in Kubernetes 1.25. Its replacement is Pod Security Admission, a built-in plugin that enforces a set of published rules called the Pod Security Standards. It is much simpler: you choose a level for each namespace by adding labels to that namespace.

Three Levels

Privileged

No restrictions at all. Meant for trusted system components, such as storage drivers and networking agents, that genuinely need deep access to the node.

Baseline

Blocks the most dangerous settings, such as sharing the host network or running fully privileged containers, while staying friendly to typical applications that were not written with security in mind.

Restricted

Follows current hardening best practice, for example requiring containers to run as a non-root user, dropping extra Linux capabilities, and using a default seccomp profile. This is the target for new applications.

Three Modes

For each namespace you can choose how a violation is handled, and you can use more than one mode at the same time. Enforce rejects violating Pods. Audit allows them but records the violation in the audit log. Warn allows them but shows a warning to the user. A very effective migration plan is to enforce at baseline while auditing and warning at restricted, so teams see what they must fix before the stricter level is switched on.

1

Start with Warn and Audit

Label namespaces to warn and audit at the target level. Nothing breaks, but you learn which workloads would fail.

2

Fix the Workloads

Work with application teams to adjust the flagged settings. Most fixes are small, such as choosing a non-root user.

3

Turn on Enforce

When the warnings go quiet, switch the namespace to enforce. New violations are now blocked at the door.

i
Good to Know

Pod Security Admission looks at Pods, and it also checks the Pod templates inside higher-level objects when you use warn and audit modes. Enforce mode applies only to Pods themselves, so a Deployment may be accepted even though its Pods are later refused. Watch for Deployments that show fewer running Pods than expected.

12Inside the API Server: The Admission Chain

So far we have treated admission as one box. Now we open the box and see how the individual plugins are lined up, who calls whom, and why a single user action can trigger several rounds of admission.

A Chain of Small Decisions

Inside the API server, admission is not one big program. It is a chain of small plugins, and each plugin is asked about the request in turn. The built-in plugins are compiled into the server and run first or alongside the extension points. The webhook plugin is itself just another link in the chain: when its turn comes, it looks at all the registered webhooks, filters out the ones that do not match the request, and calls the rest.

The order of the built-in plugins is fixed by the server, and you should not try to depend on it. Likewise, when several mutating webhooks match the same request, you should not write one webhook that silently relies on another having run first. If two mutations really depend on each other, merge them into one component. Code that works only because of an accidental order tends to break during upgrades, when ordering details change.

Simple Analogy

Think of airport security. Your bag goes through several stations: a document check, an X-ray, a liquids check, and a random swab test. Each station is small and focused, and any one of them can stop you. No station knows how the others work, and the airport may rearrange them from time to time. A passenger who only sees “security” does not notice the chain, but anyone designing the airport must.

One Action, Many Requests

A very common surprise is that one human action produces several API requests, and each of them goes through admission separately. When you create a Deployment, the Deployment controller creates a ReplicaSet, and the ReplicaSet controller creates Pods. These controllers are programs inside the cluster, and they talk to the API server just like you do. That means your Deployment is checked once, the ReplicaSet is checked again, and each Pod is checked a third time.

This is why the rule coverage matters so much. A rule that blocks bad Pods will fire even if the bad settings were hidden inside a Deployment template, but the error will appear in the ReplicaSet events rather than in your command output. The Deployment itself may look healthy, with the Pods simply never appearing. Knowing the chain makes this behavior easy to diagnose.

flowchart TD
    U["User creates a Deployment"] --> A1["Admission check 1: Deployment"]
    A1 --> D["Deployment controller"]
    D --> A2["Admission check 2: ReplicaSet"]
    A2 --> R["ReplicaSet controller"]
    R --> A3["Admission check 3: Pod"]
    A3 --> P["Pod stored and scheduled"]
    A3 -. "rejected" .-> E["Event on the ReplicaSet"]
        
FIG 4 — One user action passes through admission several times

What Each Plugin Sees

Each plugin receives a structured description of the request: who is calling, which resource, what operation, and the object itself. Plugins do not see the network connection, the command the user typed, or the tool used. A request from a command-line tool, a pipeline, or a controller looks the same except for the caller identity. This is a feature, not a limitation, because rules apply equally to every path into the cluster.

i
Debugging Tip

When a Deployment seems stuck, look at the ReplicaSet and its events before looking at the webhook. The denial message from admission is usually recorded there, because the ReplicaSet controller was the caller that received the rejection.

13Subresources, Updates, and Deletes: The Tricky Corners

Creating a new object is the easy case. Most real-world surprises come from the other operations, and from the parts of an object that have their own separate address.

Subresources

Many objects have subresources, which are special sub-addresses for particular actions. A Pod has a status subresource used by node agents to report health, an ephemeral containers subresource used for debugging, and connection subresources used for opening a shell or forwarding a port. A Deployment has a scale subresource that autoscalers use to change the replica count. An eviction subresource is used when draining nodes.

Why does this matter for admission? Because a rule written for a Pod does not automatically cover its subresources. The registration must name the subresource explicitly, or it will not be consulted. If you want to stop engineers from opening shells inside production containers, you must write a rule about the connection subresource, not about the Pod itself. A surprisingly large number of security gaps come from rules that forgot the subresources.

Updates Need Two Versions

An update request carries both the new object and the old one. This is powerful, because a rule can compare them. A rule can say “the storage size may grow but never shrink,” or “the owner label may never change after creation.” Without the old object you could only judge the new state, which cannot express the idea of a forbidden change.

There is a trap, though. Controllers constantly update objects to record their own progress: a status here, a counter there. If your rule is too strict about updates, you can accidentally block the cluster’s own housekeeping. Rules that apply to updates should be as narrow as possible, and they should usually ignore changes that only touch the status subresource.

Create

Judge the New Object

There is no old version. Rules check that the new object follows policy from the start.

Update

Compare Old and New

Rules can forbid specific changes, protect fields that must stay constant, and avoid blocking routine controller writes.

Delete

Protect What Matters

Rules can stop the deletion of critical objects, such as a production namespace or a shared database claim, until a human removes a protection marker.

Connect

Watch Sensitive Actions

Rules can log or block shell access and port forwarding to selected workloads, giving a clear trail of who entered what.

Deletes Are Admission Events Too

Admission also sees delete requests. Teams use this to build a safety net: for example, a rule that refuses to delete a namespace unless it carries a label saying deletion is approved. Remember that the old object is available for deletes, so the rule can examine what is about to be removed.

ANTI-PATTERN-04 Avoid
Problem

A strict update rule is applied to every change of a resource, including the progress updates written by controllers and autoscalers.

Why It’s Harmful

Controllers cannot record their progress, scaling stops working, and rollouts appear frozen. The root cause is hard to spot because the denials are written by system components, not by people.

Correct Approach

Limit update rules to the fields you truly care about, exclude status changes, and exempt trusted system identities where appropriate. Test the rule by running a normal rollout and a scaling event in a staging cluster.

14Testing Rules Safely: Dry Run and Staging

An untested admission rule is a risk to the whole cluster. Fortunately, Kubernetes gives you several ways to rehearse a rule before it matters.

Server-side Dry Run

Most clients can send a request in dry-run mode. The API server then does everything it would normally do, including authentication, authorization, every admission step, and validation, but it stops before saving anything. The response tells you what would have happened. This makes dry run the best everyday tool for testing a rule: apply a sample object in dry-run mode and see whether it is accepted, changed, or rejected.

Because dry-run requests pass through webhooks, remember that your webhook must honor the dry-run flag. A webhook that sends an email or writes to an external database on every request would do so even for a rehearsal, which defeats the purpose. That is why the side effects declaration exists.

A Practical Test Plan

1

Collect Good and Bad Examples

Write a small set of objects that should pass and another set that should be rejected. Keep these files with the policy so they grow together.

2

Run Them in Dry-Run Mode

Send each example against a test cluster and confirm the result matches what you expect. Check that the denial messages are readable.

3

Test the Awkward Cases

Try updates, deletes, subresources, and objects created by controllers, not only direct creates by a person.

4

Simulate Failure

Stop the webhook, expire its certificate in the test environment, and slow it down. Observe whether the cluster behaves as you intended.

5

Promote in Stages

Move from a development cluster to staging and then to production, with audit or warn mode first at each step.

Use Case: A Pipeline That Tests Policies

A platform team keeps all rules and their sample files in one repository. Every proposed change triggers an automatic run that applies the good and bad samples to a temporary test cluster. A change that lets a bad sample through, or blocks a good one, fails the build and never reaches production.

!
Do Not Skip Staging

A rule that looks harmless on paper can block system components you forgot about, such as networking agents or storage drivers. A staging cluster that resembles production reveals these surprises while they are still cheap to fix.

15Security Considerations

Admission controllers sit in one of the most powerful positions in the cluster, which makes them both a strong defense and an attractive target.

The Webhook Is a Powerful Citizen

A mutating webhook can change any object that matches its rules. If an attacker takes control of your webhook service, they can quietly rewrite workloads, for example by changing the image a Pod runs or adding a malicious container. A validating webhook under attacker control could approve anything. That is why the service must be treated as part of the control plane in terms of care, even though it is just a Deployment.

Simple Analogy

Imagine the front desk guard who stamps and approves every package. If a thief replaces that guard, the thief now controls everything entering the building. So the guard’s uniform, key, and phone line must be protected more carefully than any ordinary employee’s.

Protect

Lock Down the Service

Run the webhook with a minimal service account, a restrictive network policy that only lets the API server reach it, and no unnecessary permissions.

Protect

Guard the Registration

Only a few trusted administrators should be able to create or edit webhook registration objects, since changing one can disable or redirect all checks.

Protect

Protect the Certificates

Keep private keys in secrets with tight access, rotate them on a schedule, and monitor expiry so renewals never come as a surprise.

Protect

Trust Only the Object

Treat all fields in the request as untrusted input. Validate carefully, and avoid decisions based on easily forged labels alone.

Policies Can Be Bypassed If You Are Not Careful

A rule is only as strong as its coverage. If a rule checks Pods but not Deployments, a user could try to sidestep it by creating the higher-level object in a way that produces a bad Pod later. If a rule is excluded for certain namespaces, anyone who can create objects in those namespaces can ignore it. Review exclusions regularly and keep them as short as possible.

Also remember that admission controllers only see requests, not existing state. A new rule does not fix old objects. Combine admission with periodic scanning, which most policy engines offer, to find existing violations.

!
Common Mistake

Giving the webhook service broad cluster-admin rights “to be safe.” The opposite is true: a compromised service with wide rights is a direct path to the whole cluster. Grant only what it must have.

16Reliability and Performance

Because admission sits in the middle of every matching write, a slow or broken webhook slows or breaks the entire cluster.

Latency Adds Up

Each webhook call happens while a user waits. If three webhooks each take half a second, every matching request becomes one and a half seconds slower. Worse, controllers inside the cluster also write objects constantly, so a slow webhook can create a backlog that affects scaling, rollouts, and recovery. Keep webhook logic small, avoid calling other services during a decision when possible, and cache anything you must look up.

Milliseconds
Target answer time for a healthy webhook
3+
Replicas recommended for important webhooks
Spread
Pods across nodes and zones to survive failures

Availability Practices

1

Run Multiple Replicas

A single webhook Pod is a single point of failure for every request it guards. Run several, and add a disruption budget so maintenance never takes them all down at once.

2

Spread Across Failure Zones

Use scheduling rules so replicas land on different nodes and, when possible, different availability zones, so one failure cannot remove the whole service.

3

Give It Priority

Assign a high priority class so that under resource pressure the webhook Pods are among the last to be evicted.

4

Narrow the Scope

Match only what you truly need using rules, selectors, and match conditions. Fewer calls means less load and fewer chances to fail.

5

Test the Outage

Deliberately stop the webhook in a test cluster and observe. Learn the real effect of your failure policy before an incident teaches it to you.

i
Why Native Policies Help

Since policies written in CEL run inside the API server, they remove an entire class of failures: no network hop, no certificate expiry, no missing service. For simple rules, this is a real reliability win.

17Monitoring, Logging, and Metrics

You cannot manage what you cannot see. Admission control gives you several windows into what is happening.

Metrics from the API Server

The API server publishes metrics that describe admission activity. They include the time spent in each admission step, the time spent calling each webhook, counts of rejected requests, and counts of requests that were let through because a webhook failed while set to fail open. Collect these in your monitoring system and chart them. A sudden rise in webhook duration or in rejections is often the first sign of trouble.

Watch

Webhook Duration

How long each webhook takes to answer. Alert when it climbs, because users will feel it before you do.

Watch

Rejection Count

How often requests are denied, broken down by webhook. A spike may mean a new rule or a broken deployment pipeline.

Watch

Fail-Open Count

How many requests skipped a check because the webhook was unreachable. Any steady number deserves an investigation.

Watch

Certificate Expiry

Days remaining on the webhook certificate. Alert well ahead of the date so renewal is never an emergency.

Audit Logs and Annotations

The cluster audit log records requests, and admission decisions can add annotations to those entries. When a policy audits a violation, or a webhook returns audit annotations, the note appears next to the request. This gives security teams a searchable trail of who tried to do what, and which rule reacted.

Logging Inside the Webhook

Your own service should log each decision with the request ID, the resource, the user, and the outcome, while avoiding the logging of sensitive data from Secrets or tokens. When a developer says “my deployment was rejected,” a log search by request ID should answer within a minute.

flowchart TD
    R["Incoming request"] --> A["API server admission step"]
    A --> M["Metrics: duration and rejections"]
    A --> L["Audit log with annotations"]
    A --> W["Webhook service logs"]
    M --> D["Dashboards and alerts"]
    L --> S["Security review"]
    W --> T["Troubleshooting"]
        
FIG 3 — Three sources of visibility for admission decisions

18Design Patterns and Anti-patterns

Teams that use admission control for years tend to converge on the same good habits, and to repeat the same mistakes.

Patterns Worth Copying

Pattern: Warn, Then Enforce

Introduce every new rule in warn or audit mode first. Publish a date, let teams fix their configuration, and only then switch to deny. This keeps goodwill high and surprises low.

Pattern: Guardrails, Not Gates

Design rules to prevent clearly dangerous outcomes, such as privileged containers or missing resource limits, instead of trying to control every preference. Fewer, clearer rules are easier to explain and to keep.

Pattern: Helpful Error Messages

Every denial should name the rule, explain why it exists, and say how to comply. A good message turns a blocked developer into a self-sufficient one.

Pattern: Policy as Code

Keep policies in version control, review changes like any other code, and promote them from test to production clusters through the same pipeline as applications.

Pattern: Idempotent Mutation

Write mutations so that running them twice produces the same result as running them once. This keeps reinvocation and retries safe.

ANTI-PATTERN-02 Avoid
Problem

Using mutating webhooks to silently “fix” configurations, for example overwriting a value the developer set on purpose.

Why It’s Harmful

The running object no longer matches what the developer wrote. Debugging becomes confusing, deployment tools may keep fighting the webhook over the difference, and trust in the platform drops.

Correct Approach

Mutate only to fill in missing values or to add clearly documented injections. When a value is wrong, reject it with a clear message instead of changing it behind the scenes.

ANTI-PATTERN-03 Avoid
Problem

Creating a long chain of independent webhooks, each owned by a different team, with no overall plan.

Why It’s Harmful

Latency adds up, mutation order produces surprising results, and nobody knows which component caused a rejection. Outages in any one webhook can block the whole cluster.

Correct Approach

Consolidate rules into a small number of well-owned components, prefer native policies for simple checks, and document who owns each registration.

“A good admission rule is a guardrail that explains itself, not a locked door with no sign.”

19Best Practices and Common Mistakes

A condensed checklist of what works, and of the traps that catch even experienced teams.

Best Practices

  • Prefer built-in plugins and native CEL policies before building custom webhooks
  • Choose the failure policy deliberately for each webhook
  • Exclude system namespaces and the webhook’s own namespace
  • Keep decisions fast and free of slow external calls
  • Run several replicas with disruption budgets
  • Automate certificate renewal and alert on expiry
  • Roll out new rules with warn and audit first
  • Test policies in a staging cluster before production

Common Mistakes

  • Forgetting that admission ignores objects that already exist
  • Letting certificates expire and blocking the cluster
  • Matching every resource when only a few are needed
  • Writing vague denial messages that frustrate users
  • Declaring no side effects while actually causing some
  • Trusting labels that any user can set freely
  • Running a single webhook replica for a critical rule

A Safe Rollout Plan for a New Rule

1

Define the Goal

Write down what harm the rule prevents. If you cannot explain it in a sentence, the rule is probably too complicated.

2

Try It in Audit Mode

Apply it so violations are only recorded. Read the audit results to see who would be affected.

3

Add Warnings and Announce

Turn on warnings, tell teams the enforcement date, and offer help for the common fixes.

4

Enforce and Monitor

Switch to deny, watch rejection counts closely for the first days, and keep a quick path to roll back if something unexpected breaks.

20Real-World Examples

Admission control is not a theory topic. Several tools you may already use depend on it every day.

Service Meshes Such as Istio and Linkerd

These meshes use a mutating webhook to add a proxy container to Pods in labeled namespaces. Developers deploy ordinary applications, and the proxy that provides encryption and traffic control appears automatically.

Secret Delivery with Vault Agent Injector

HashiCorp Vault can add an agent container to Pods that carry specific annotations, so credentials are fetched and delivered to the application without the developer writing integration code.

Certificate Management with cert-manager

cert-manager uses its own webhook to validate the certificate-related objects people create, rejecting malformed requests early with a clear message instead of failing later in the process.

Platform Guardrails with Kyverno or Gatekeeper

Platform teams in many companies use these engines to require ownership labels, restrict image registries, demand resource limits, and block risky settings, making the paved road the easy road for every application team.

Multi-Tenant Clusters

When several teams share a cluster, resource quotas, limit ranges, and Pod Security levels per namespace work together so that each team gets a fair, safe slice without constant manual review.

i
Notice the Pattern

In every example, the person deploying never has to remember the rule. The cluster remembers for them, consistently, every time. That is the real value of admission control.

21Troubleshooting Admission Problems

When something is rejected or the cluster feels stuck, a calm, step-by-step approach finds the cause quickly.

When a Request Is Rejected

Start with the error message itself. Webhook denials include the name of the webhook and the message it returned. Native policy denials name the policy and the failed rule. If the message is vague, check the policy engine’s logs and the audit log for the request.

When Everything Seems Blocked

If many unrelated requests are failing with errors that mention a webhook call failing, the webhook service is probably unreachable. Check whether its Pods are running, whether its Service has healthy endpoints, and whether its certificate is still valid. Remember that a webhook set to fail closed will block every matching request while it is down.

1

Read the Error Text

It names the webhook or policy responsible. That tells you where to look next.

2

Check the Service Health

Confirm that the webhook Pods are ready, the Service has endpoints, and nothing blocks traffic from the API server.

3

Verify the Certificate

Look at expiry dates and confirm the registration holds the correct certificate authority.

4

Inspect the Registration

Review its rules, selectors, and failure policy to see why the request was sent to it at all.

5

Use the Emergency Exit if Needed

If the cluster is truly stuck, an administrator can temporarily remove or loosen the registration object to restore normal operation, then fix the root cause and restore it.

!
Be Careful with Emergency Removal

Removing a security webhook opens a window with no protection. Do it only with approval, keep the window short, and review what was created in the meantime once the rule is back.

22Admission Control Compared with Other Guardrails

Admission control is one guardrail among several. Understanding what the others do keeps you from asking admission to solve problems that belong elsewhere.

Each Layer Has Its Own Job

A healthy platform layers its defenses. RBAC answers who may perform which action. Network policies decide which Pods may talk to which other Pods. Admission control checks the content of objects as they enter. Scanning in the delivery pipeline catches problems before a change even reaches the cluster. Runtime security tools watch what containers actually do after they start. No single layer can replace the others, and removing one leaves a gap that the rest cannot fill.

LayerQuestion It AnswersWhen It ActsBlind Spot
RBACIs this caller allowed to do this action?Before admissionCannot judge object contents
Admission controlIs this specific object acceptable?When the request arrivesIgnores existing objects and runtime behavior
Network policyWho may talk to whom?While traffic flowsSays nothing about object settings
Pipeline scanningDoes the change look safe before deploying?Before the clusterCan be bypassed by direct access
Runtime securityIs a container behaving badly now?After startReacts late, after the workload runs
Simple Analogy

Consider a bank. The ID check at the door is RBAC, the teller reviewing each form is admission control, the cameras and alarms inside are runtime security, and the audit done before the form is even handed over is pipeline scanning. A bank with only one of these would be easy to rob.

Validation Rules in Custom Resources

Kubernetes also lets authors of custom resource types embed validation rules, written in CEL, directly in the type definition. These rules travel with the type, so every cluster that installs it gets the same checks. They are the right place for rules that describe what a valid object of that type means, such as “the maximum must not be smaller than the minimum.” Admission policies, in contrast, are the right place for rules that describe your organization’s preferences, which can differ between clusters.

i
Where Should the Rule Live?

If a rule is true for everyone who uses an object type, put it in the type. If it reflects your company’s policy, put it in an admission policy. If it checks who may act, use RBAC. Placing each rule in the right layer keeps the system understandable.

23A Complete Walkthrough: Guardrails for a Shared Cluster

Let us put everything together with a story. A platform team runs one cluster used by several product teams and wants safe defaults without slowing anyone down.

The Situation

The platform team supports about a dozen application teams. Incidents keep repeating: a Pod without memory limits crashes a node, an image from an unknown registry is deployed, and nobody knows who owns a mysterious workload. The team decides to use admission control to address the three problems, without becoming a bottleneck.

1

Start with Built-ins

They enable quotas and limit ranges per namespace so each team has a defined budget and every container gets sensible default limits. No custom code is needed, and the memory incidents drop right away.

2

Turn On Pod Security in Warn Mode

They label every application namespace to warn at the restricted level and enforce at baseline. Teams see warnings in their normal deploy output and begin fixing their Pod settings over the following weeks.

3

Add a CEL Policy for Ownership

A native validating policy requires an owner label on every workload. It starts in warn mode, with a clear message explaining the label and pointing to a short guide. The binding applies only to application namespaces.

4

Use a Policy Engine for the Registry Rule

Restricting images to approved registries needs a list that changes often, so they use a policy engine that supports exceptions and reports on existing violations. The engine runs several replicas with a considered failure policy.

5

Announce, Then Enforce

After a published grace period, the warnings turn into denials one rule at a time. Dashboards track rejection counts, and a support channel handles questions during the first week.

6

Review Every Quarter

The team reviews exclusions, retires rules that no longer help, checks certificate renewals, and verifies that policies still work on the current cluster version.

What They Did Right

Chose the Lightest Tool for Each Rule

Built-in plugins for quotas, native policies for object-only checks, and a policy engine only where outside data and exceptions were needed. Each choice reduced moving parts.

Treated People as Users

Every denial explained itself, every rule had a warning period, and the team answered questions quickly. The result was cooperation instead of workarounds.

Kept Visibility

Metrics, audit logs, and reports on existing objects meant the team could always say which rule fired and why, and could find old violations that admission alone would have missed.

24Upgrades, Versions, and Long-Term Maintenance

Admission rules are not a one-time project. Clusters, tools, and certificates all change, and rules must keep up.

Cluster Upgrades

Kubernetes releases new versions several times per year. Each release can promote features from experimental to stable, deprecate old interfaces, and eventually remove them. Admission is touched by these changes in several ways. A policy feature may become available only after you upgrade. The message format used by webhooks may gain a new stable version while an old one is removed. A built-in plugin may change its default behavior. Reading release notes with admission in mind should be a standard step of every upgrade.

Check

Webhook Message Versions

Confirm your webhook service understands the current stable message version before the cluster is upgraded.

Check

Feature Availability

Verify that any policy features you rely on are available and enabled on the target version, especially newer ones.

Check

Policy Engine Compatibility

Make sure the engine version you run supports the new cluster version, and upgrade it in a safe order.

Check

Behavior During the Upgrade

During a control plane upgrade, API servers restart one at a time. Confirm that webhook availability and failure policies keep working through the transition.

Keeping Rules Healthy

Rules grow stale. Teams change, tools are retired, and exceptions pile up. A rule created for a long-forgotten incident can keep blocking a legitimate new workflow. Assign an owner to every rule and webhook, record why it exists, and review the list on a schedule. Retire rules that no longer protect against a real risk, because every extra rule adds latency, confusion, and potential failure.

ANTI-PATTERN-05 Avoid
Problem

A webhook is installed, works well for a year, and is then forgotten. Nobody owns it, its certificate is set to expire, and its container image is never updated.

Why It’s Harmful

One day the certificate expires, the API server cannot reach the service, and a fail-closed webhook blocks all matching requests. The people on call do not know the webhook exists, let alone how to fix it.

Correct Approach

Name an owning team, automate certificate renewal, include the webhook in regular patching, add alerts for expiry and latency, and document an emergency procedure.

25Capacity Planning: The Cost of Admission

Every check has a price. Planning for that price early prevents slow clusters and surprising outages later.

Where the Time Goes

Built-in plugins and native policies run inside the API server and are usually very cheap. Webhooks add a network round trip, the time your service needs to think, and the cost of encrypting the connection. If many matching requests arrive at once, such as during a large rollout or when a node fails and hundreds of Pods are recreated, the webhook sees a burst of traffic that is far higher than its normal level.

Bursts
Rollouts and node failures create sudden spikes of requests
Tail
Slowest answers matter more than the average
Shared
One slow webhook delays every matching request

Sizing a Webhook Service

1

Measure the Real Request Rate

Look at the API server metrics for how many matching requests arrive normally and at their peaks, not only on a quiet day.

2

Load Test the Webhook

Send bursts at the service in a test environment and watch its answer times. Find the point where it slows down and keep a comfortable margin below it.

3

Watch the Slowest Answers

Track the slowest few percent of answers, not just the average. The slow tail is what users and controllers feel during busy moments.

4

Reduce What Reaches It

Tighten rules and selectors so only the necessary requests are sent. This is cheaper than adding more replicas.

5

Scale Automatically with Care

Use automatic scaling where it helps, but keep a healthy minimum number of replicas, because scaling up takes time and the burst may arrive faster.

!
Watch the Feedback Loop

A slow webhook can slow down the controllers that create Pods, which delays recovery, which creates more requests. During an incident this loop makes things worse. Keeping webhooks fast and well provisioned is part of keeping the cluster resilient.

26A Decision Guide: Choosing the Right Mechanism

With so many options, a simple decision path helps teams pick a tool without a long debate.

flowchart TD
    S["New rule needed"] --> Q1{"Does a built-in plugin already do this?"}
    Q1 -- "Yes" --> B["Enable and configure the built-in plugin"]
    Q1 -- "No" --> Q2{"Does the rule need only the object itself?"}
    Q2 -- "Yes" --> Q3{"Validate or change?"}
    Q3 -- "Validate" --> V["Native validating policy with CEL"]
    Q3 -- "Change" --> M["Mutating policy if available, otherwise webhook"]
    Q2 -- "No" --> Q4{"Is it one of many rules needing exceptions and reports?"}
    Q4 -- "Yes" --> P["Policy engine"]
    Q4 -- "No" --> W["Custom webhook with care"]
        
FIG 5 — A decision path for choosing an admission mechanism

Reading the Chart in Words

First ask whether Kubernetes already does what you want. Quotas, default limits, default storage classes, and Pod security levels are built in, and using them costs almost nothing. If nothing built in fits, ask whether the rule depends only on the object. If it does, a native CEL policy is the simplest and most reliable choice. Only when you need outside information, complex generated content, or a whole family of managed rules with exceptions and reporting do you move to policy engines or custom webhooks.

A Few Final Checks Before You Ship

Ready to Ship When

  • The rule has a clear owner and a written purpose
  • Good and bad samples pass tests in staging
  • The failure policy was chosen and tested on purpose
  • Denial messages explain how to comply
  • Metrics, alerts, and audit visibility are in place
  • A rollback path is documented

Not Ready If

  • Nobody can say who owns the rule
  • It was never tested against updates and subresources
  • It has no warning period for existing teams
  • The webhook runs as a single replica
  • Certificate renewal is manual

27Frequently Asked Questions

Q1Do admission controllers run on read requests like get or list?

No. They apply to create, update, delete, and connect operations only. Reading data is controlled by authorization, not admission.

Q2What is the difference between authorization and admission?

Authorization decides whether you may perform a kind of action on a kind of resource. Admission examines the specific object in the request and can change it or reject it based on its contents.

Q3Will a new admission rule fix objects that already exist?

No. Admission only sees incoming requests. Existing objects are untouched until someone updates them. Use scanning or reporting features to find existing violations.

Q4Can I add or remove built-in plugins on a managed cluster?

Usually not. Cloud providers control the API server settings. This is why webhooks and native policies, which need no API server changes, are so widely used.

Q5Should my webhook fail open or fail closed?

Fail closed for controls that protect security or compliance, and fail open for optional conveniences. Whatever you choose, run multiple replicas and test what happens during an outage.

Q6Do validating checks see changes made by mutating webhooks?

Yes. All mutation completes first, so validation judges the final object that would be stored.

Q7When should I choose a CEL policy instead of a webhook?

Choose a CEL policy when the rule needs only the object itself, and choose a webhook when you must consult outside data or need complex logic that CEL cannot express.

Q8Why did my Deployment succeed but no Pods appear?

The Deployment was accepted, but the Pods it tried to create were rejected, often by Pod Security Admission or a policy. Check the events and the status of the related ReplicaSet to see the denial message.

Q9Can a webhook block its own restart?

Yes, if it is set to fail closed and its own namespace is not excluded. Always exclude the webhook’s namespace and the system namespaces from its scope.

Q10Do dry-run requests go through admission?

Yes. That is why webhooks must declare whether they have side effects, and why they must avoid those effects when a request is marked as a dry run.

Q11Can one request be rejected by more than one rule?

Yes. Every matching validating rule is consulted, and the request is accepted only if all of them approve. The user may see one or several denial messages, so each message should stand alone and explain its own rule clearly.

Q12Do controllers inside the cluster go through admission too?

Yes. Controllers talk to the API server like any other client, so the ReplicaSets and Pods they create are checked separately from the Deployment you submitted. Rules must therefore tolerate normal controller behavior, including routine status updates.

Q13What happens to existing Pods when a new rule is added?

Nothing. Running Pods keep running exactly as they are. The rule applies the next time something creates or updates a matching object, which is why scanning and reports are needed to find older violations.

Q14Why does my rule not stop people opening a shell in a container?

Shell access uses a connection subresource of the Pod. A rule written only for the Pod itself does not cover it, so the registration must name the subresource explicitly.

Q15Is it safe to exclude the system namespaces from every rule?

It is the safe default for rules that could block critical components, but exclusions should be kept short and reviewed. Anyone who can create objects in an excluded namespace can bypass the rule there, so control access to those namespaces tightly.

Q16How do I roll back a rule that is causing trouble?

Switch it from deny to warn or audit mode, or remove its binding or registration. Because rules are objects stored in version control, rollback is usually a quick, reviewed change. Keep that procedure documented before you need it.

Q17Should every team write its own webhook?

Usually not. A few well-owned components, native policies, and a shared policy engine are easier to secure, monitor, and keep available than many separate webhooks. Offer teams a simple way to request or propose rules instead.

Q18How should I word a denial message?

State which rule was broken, explain in one sentence why the rule exists, and tell the person exactly what to change. A message that names the field, the allowed values, and a link to internal guidance saves a support conversation every time.

Q19Who should own admission rules in a large company?

A small platform or security team should own the shared rules and the tooling, while application teams propose changes through the normal review process. Clear ownership means someone always answers when a rule blocks a deployment or a certificate is about to expire.

28Summary and Key Takeaways

Admission controllers are the cluster’s last checkpoint before an object is stored. They run after authentication and authorization, first changing requests where allowed, then validating the final result. Built-in plugins handle common needs such as defaults, quotas, and Pod security. Webhooks extend the system with your own logic, while CEL-based policies and policy engines make common rules simpler and safer to run. Used thoughtfully, with clear messages, careful failure settings, and good monitoring, admission control turns your cluster rules from a document people forget into behavior the platform guarantees.

Key Takeaways

  • Admission is a content check — it runs after authentication and authorization and examines the actual object being created, updated, deleted, or connected to.
  • Mutate first, validate last — all changes happen before the final checks, so validators always judge the object that would really be stored.
  • Prefer simple tools first — built-in plugins and native CEL policies avoid the cost and risk of running your own webhook service.
  • Choose failure behavior on purpose — decide between fail open and fail closed for each webhook, exclude system namespaces, and test real outages.
  • Treat webhooks as control-plane components — secure them, run several replicas, keep answers fast, and automate certificate renewal.
  • Roll out gradually — use warn and audit modes before enforcing, and write denial messages that tell people how to fix the problem.
  • Remember the limits — admission sees only new requests, so pair it with scanning to find old violations and keep visibility through metrics and audit logs.