Admission: mutate safely, then validate the resulting object
Separate authentication, authorization, mutation, validation, and persistence while handling reinvocation and webhook failure deliberately.
On this page
The question for today
What you’ll understand
- Explain why validation must consider the post-mutation object.
- Design an idempotent defaulting mutation under possible reinvocation.
- Distinguish explicit policy denial from webhook transport failure.
Admission is part of accepting an API request, not the reconciliation loop that later makes the world match it. In the v1.34 model used here, admission runs after authentication and authorization and before object persistence for applicable requests. Mutation can add or change fields, while validation decides whether the resulting request is allowed. A correct policy must account for the actual phase boundaries and must not depend on a fragile guess about the ordering of independent webhooks.
A mutation changes what later policy sees
Consider an object requesting 300 units with no limit. A mutator may supply a default limit of 400, after which validation checks that the request does not exceed the limit. A validator looking only at the original missing field would answer a different question. Kubernetes separates mutating and validating admission stages so final validation can assess the resulting object. Admission is still not a transaction with every external service a webhook might contact, and acceptance of a desired resource does not prove that its workloads are already running.
Multiple mutation policies can interact: one may add a container after another supplied defaults for existing containers. Mutating webhooks must be idempotent and must not assume a globally fixed invocation order that makes every policy interaction safe. The configured reinvocationPolicy may permit additional calls when later mutations change the object; the number of additional calls is not a guaranteed exactly-once repair round. Put invariants that require the final object in validation and design mutation to tolerate fields already having the intended values.
Failure policy is not permission to ignore a denial
A webhook can explicitly deny a request with a valid admission response, or it can fail to respond successfully because of timeout, transport error, or malformed output. failurePolicy controls applicable call failures; it does not transform a properly transmitted explicit denial into approval. Choosing Ignore for a critical policy therefore changes the outcome during an outage, while choosing Fail adds the webhook’s availability to that request path. Document the intended behavior and keep the webhook fast and operationally independent enough to meet it.
A webhook should avoid irreversible external actions during admission. The API write can still fail or be rejected later, leaving an external reservation without a corresponding object. Dry-run requests also require correct side-effect declarations and behavior. Prefer validating supplied facts and supplying defaults, then let a controller perform repeatable external reconciliation after persistence. If a policy depends on mutable external state, specify the consistency and race limitations instead of assuming an admission-time lookup freezes that state until the workload executes.
Test the composition rather than isolated happy paths
Test a mutator twice on already defaulted input, apply supported policy orderings, and validate the resulting object. Test explicit denial separately from call timeout under each failure policy. Include dry-run, object updates as well as creates, and namespace or object selectors that change which webhook matches. Inspect audit or diagnostic evidence for which mutations actually ran. A policy that passes its own unit tests can still conflict with another mutator by repeatedly undoing its change, creating rejection loops or excessive latency.
The network lab illustrates a composed calculation before a separate decision. Reset, set input x=1 and weight w=1, predict sigmoid(0.5)≈0.622, then Step. Compare that output with a hypothetical human-applied threshold of 0.5. The instrument itself has only one sigmoid graph; it does not run admission, mutate an object, invoke webhooks, or implement validation. Its limited point is that a decision based on a transformed value must inspect that resulting value rather than the untransformed input.
Work it through
An idempotent default survives another call
An object requests 300 abstract capacity units and has no limit. Policy M sets a missing limit to 400 without changing an existing limit. Policy V requires request≤limit. Compare with a bad mutator that increments a limit by 100 on every call.
Applying M once supplies limit 400. Validation checks 300≤400 and accepts this numeric condition. A second call to M leaves the existing limit at 400, so the result is unchanged.
For comparison, start the bad incrementing mutator with limit 400. One call produces 500 and a second 600. Both may satisfy this simple inequality, but the mutation is not idempotent and its outcome depends on invocation count.
A final validation phase must evaluate the actual post-mutation object and any other required policies. Satisfying one numeric inequality does not bypass authentication, authorization, schema checks, or another validator’s explicit denial.
Set a default when absent rather than accumulate a new side effect on every invocation. Final validation evaluates the completed mutation result.
The living notebook
Explore the model
Interactive lab · network
Evaluate the transformed value
Reset, set x=1 and w=1, predict σ(0.5)≈0.622, then Step. Compare the result yourself with 0.5. The fixed sigmoid graph does not implement admission, object mutation, webhook ordering, or a validator.
- Product · wx
- 1.2
- Logit · wx − 0.5
- 0.7
- Sigmoid output
- 0.6682
One inspectable sigmoid unit, σ(wx − 0.5). Playback traces the computation graph. There is no training, attention mechanism or hidden deep network. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA downstream decision must be based on the value actually produced by the preceding computation.
Pause & reason
Check your understanding
Your turn
Try it yourself
Two mandatory remote calls are deliberately serial and take 30 ms and 50 ms. What is their summed latency contribution? If the second explicitly denies, does failurePolicy=Ignore necessarily permit the request?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Keep the constructed serial assumption and distinguish denial from failed communication.
Compare with the solution
The two calls contribute at least 80 ms before other overhead in this serial example. A properly returned explicit denial still rejects; Ignore applies to the configured classes of call failure, not to a successful policy response that says no.
Keep the idea
Take it with you
- Admission phases and reconciliation fulfill different responsibilities.
- Mutation must tolerate existing fields and possible reinvocation.
- Explicit denial, transport failure, dry-run, and external side effects need distinct policies.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.