
TL;DR
A Kubernetes admission rule can establish that a proposed value is permitted without establishing that this particular action is currently approved. Bind approval to the exact operation, target identity, relevant starting state, initiating authority, execution identity, and validity window. Keep approval consumption and uncertain execution in a protected record outside the agent.
This companion preserves the previous Kubernetes Boundary Kit and adds an offline builder for conditional requests. Sixteen local construction tests passed. The builder does not issue approvals, enforce expiration, maintain an execution ledger, or call Kubernetes. The live request and workflow tests below are acceptance criteria, not reported cluster results.
Approval should authorize a bounded change, not every future request that happens to produce an acceptable value.
Introduction
An agent receives approval to change a ConfigMap from thirty to forty-five. Before execution, an administrator deletes the object and recreates another ConfigMap under the same name.
The agent submits the original patch. Its identity still has permission to patch that name. The admission policy still permits forty-five. The new object accepts the change.
The platform may have enforced both configured controls correctly. The workflow nevertheless acted on an object the reviewer never examined.
A similar problem occurs when approval expires in a queue, another worker consumes it, or the executor silently refreshes a stale resource version and retries. The final value can remain acceptable while the authorization relationship has changed.
The previous Kubernetes companion established a Kubernetes exercise using actual service-account credentials, resource-scoped permissions, admission validation, and observer readback. This installment adds the missing transaction boundary: connecting an approval to the specific change that reaches the target.
The operating design is proposed. Its executable helper addresses request construction only, while approval issuance, protected execution state, and live enforcement remain integration responsibilities.
Keep the Existing Admission Boundary Intact
The earlier kit uses an unconsumed ConfigMap named retention-fixture in rtb-boundary-lab. It begins with retentionDays: "30". Its admission policy requires the resulting data map to contain only retentionDays: "45".
Those values remain teaching fixtures, not a backup-retention policy. No application, operator, or backup product may consume this ConfigMap.
The existing agent, executor, and observer identities also retain their roles. The agent proposes; the restricted executor can patch the named object; the observer reads the result.
Do not weaken that policy to accommodate a new approval mechanism. Add the action-specific boundary around it.
| Existing control | What it addresses | What the new workflow must establish |
|---|---|---|
| Authenticated service account | Which identity submitted the API request. | Which initiating authority and approved action the executor represents. |
| Resource-scoped RBAC | Whether that identity may patch the named resource. | Whether this particular patch is currently permitted. |
| Fixed admission invariant | Whether the resulting object satisfies the configured value constraint. | Whether its target and starting conditions match the reviewed proposal. |
| Observer readback | What the observer can establish about current state. | Whether that state supports completion of this specific action. |
Role-based access control (RBAC), admission, and action approval remain complementary. None should be silently renamed to imply that it supplies all three responsibilities.
Bind the Approval to More Than the Payload
A request body containing forty-five does not identify the cluster, object, caller, or permitted execution period. Approving a payload hash alone leaves those relationships unspecified.
A proposed approval record should bind the following information through a protected, versioned request:
| Binding | Required content |
|---|---|
| Authority | Authenticated initiator, applicable delegation, approval basis, and permitted executor. |
| Destination | Governed cluster reference, resource type, namespace, name, and object UID. |
| Operation | Method, path, relevant request options, exact mutation, and adapter contract version. |
| Preconditions | Reviewed resource version and any other decision-critical starting conditions. |
| Lifetime and use | Earliest dispatch, dispatch deadline, suspension state, and permitted logical-action count. |
| Evidence | Proposal record, approval decision, execution attempts, and required observations. |
OWASP’s Transaction Authorization Cheat Sheet recommends server-side authorization, protection against modification of transaction data, controlled state transitions, and a final authorization check tied to execution. Applying those principles to an agent means the approval service must evaluate the operation, not merely accept a model’s statement that approval exists.
The existing DTD implementation pattern for human review provides the broader approval workflow. Here, the critical addition is preserving the binding as the request moves from review to execution.
Use Object Identity, Not Only Its Name
Kubernetes documents that a deleted object’s name can be reused. Its UID distinguishes the object from earlier or later objects with the same name.
Bind the reviewed UID as well as the address used to reach the object. Also bind the cluster through a governed registry and authenticated connection. A kubeconfig context name or a model-supplied cluster_ref is not proof of the destination.
The resource version adds a different condition: whether the object remains at the reviewed revision. Treat it as an opaque value. Do not interpret it as an age, timestamp, or mutation count.
Keep the Proposal and Approval Separate
Register the request as an immutable proposal. Issue a separate approval that references its identity and digest.
Do not turn the proposal into authority by changing a field from approved: false to approved: true. The approval service must establish who made that decision, what they approved, and whether it remains usable.
A digest identifies bytes. It does not authenticate the issuer, establish freshness, or prove the business decision was correct.
Put the Approval Check Where the Credentials Are Used
The agent should not receive the executor’s kubeconfig and a suggestion to use it only after approval. The credential belongs behind a separately governed execution service.
That service obtains current approval state, compares the bound request, reserves its permitted use, and controls dispatch. The target still applies native authorization and admission.
The diagram shows the additional boundary. None of the approval-service components is installed by the offline builder supplied with this article.

The controller and adapter are trusted components within this design. Their deployment identities, configuration, credentials, and administrative paths need protection from the agent.
The reliable agent tool design principle still applies: expose the bounded operation, not an arbitrary patch proxy. Otherwise, the actor can omit the preconditions that the approved path would have added.
Prepare a Conditional Request Without Authorizing It
The accompanying Bound Request Builder v0.1 reads a ConfigMap snapshot and emits one fixed thirty-to-forty-five request.
It rejects the wrong target, missing UID or revision, unexpected starting data, nonempty binary data, an immutable object, or an object marked for deletion. It also rejects duplicate JSON member names and nonfinite constants.
The helper performs no network calls. It does not establish that the snapshot is authentic or current. Obtain the snapshot through the governed observer and preserve its collection context.
Establish the Test Baseline
Use an authorized, disposable cluster and the previous kit’s supported setup. Keep its admission policy and permission boundaries intact.
A completed earlier exercise leaves the fixture at forty-five and may remove the executor’s RoleBinding. That is not this exercise’s starting state. Reconstruct the baseline through the kit’s controlled cleanup and setup procedure, with fresh credentials and evidence records. Do not give the agent permission to restore its own privileges.
The builder requires Python 3.10 or later and uses only the standard library. Local validation used Python 3.13.5 on Linux.
From the extracted builder directory, first exercise its synthetic example:
python -m unittest discover -s tests -v python build_request.py --snapshot examples/snapshot.synthetic.json --cluster-ref lab-cluster-a --action-id action-017 --output ../bound-request-demo-01
The example contains deliberately synthetic identity and revision values. It demonstrates construction, not a request to send to a cluster.
The helper creates four files: the unchanged snapshot, the conditional patch, an unapproved request record, and the digest of that request record. It refuses an existing output directory.
Sixteen local tests passed, covering construction, binding changes, malformed inputs, source preservation, and output handling. Those results do not establish approval enforcement or Kubernetes behavior.
Construct from an Observed Object
For the live precondition exercise, use the actual observer credential path and a new evidence directory. The following assumes the previous kit is a sibling directory with freshly created credentials-02 files; change those paths to match the protected environment.
umask 077 mkdir evidence-02 kubectl --kubeconfig ../rtb-kubernetes-boundary-kit/credentials-02/observer.json -n rtb-boundary-lab get configmap retention-fixture -o json > evidence-02/before.json python build_request.py --snapshot evidence-02/before.json --cluster-ref lab-cluster-a --action-id action-017 --output candidate-02
The cluster reference is an input to the proposed integration, not a verified endpoint. A real executor must resolve and validate that binding independently.
Make the Preconditions Part of the Mutation
The generated patch tests the UID, resource version, and complete starting data map before replacing that map.
This is the shape generated from the synthetic example:
[
{
"op": "test",
"path": "/metadata/uid",
"value": "synthetic-object-001"
},
{
"op": "test",
"path": "/metadata/resourceVersion",
"value": "synthetic-revision-a"
},
{
"op": "test",
"path": "/data",
"value": {"retentionDays": "30"}
},
{
"op": "replace",
"path": "/data",
"value": {"retentionDays": "45"}
}
]RFC 6902 defines the JSON Patch test operation and explains that a failed test prevents the HTTP patch from being applied successfully. Kubernetes documents conditional JSON Patch requests as a way to reject updates when required existing values do not match.
That moves the state check into the target mutation, rather than relying solely on a read performed earlier by the client.
It does not atomically validate a separate approval database. The patch protects the named object conditions; current authority remains another obligation.
Do Not Silently Refresh the Approved Revision
A common retry pattern is to read the new resource version and submit the mutation again. That can be appropriate for an ordinary reconciler. It is not automatically appropriate for an action approved against a specific earlier state.
For this workflow, a changed precondition produces a new proposal requiring reassessment. The executor must not update the bound revision while retaining the old approval.
This is intentionally conservative. An unrelated metadata change can invalidate a whole-object revision condition. A more permissive design may use narrower preconditions, but it must establish which state the decision depends on. Removing the revision check merely to reduce failed requests discards part of the protection.
Preserve the Reviewed Request Through Serialization
The builder’s request record binds the patch digest, target, path, method, request options, and adapter version. Its serialization is version-local, not a general cross-language canonicalization standard.
A production adapter must send the bound representation or implement another explicitly reviewed normalization contract. It should not append operations, select another endpoint, or reinterpret fields after approval.
Protect the artifact between verification and transmission. Reading a digest, then reopening an agent-writable file for dispatch, creates another substitution opportunity. The executor should validate and transmit the same protected representation.
Expiration Needs a Defined Enforcement Point
An approval deadline, credential expiry, and desired-state lifetime are different conditions.
In an illustrative five-minute approval window, the executor may begin an authorized dispatch before the deadline. That does not mean the resulting setting expires five minutes later. It also does not mean the API credential becomes unusable at that time.
Define the operating promise precisely.
A dispatch deadline controls when the executor may send a new mutation. A target-acceptance deadline requires enforcement at the receiving boundary. A desired-state lifetime requires later expiration or recovery behavior.
The proposed controller checks current time, suspension, approval validity, and action binding immediately before dispatch. If trusted time or required authority state is unavailable, it holds new consequential work.
There is still an interval between that check and target acceptance. A client timeout does not prove that the target rejected or canceled the request. Where the requirement is “no commitment after this instant,” identify and test the receiving mechanism that provides that guarantee. A client-side timestamp check is insufficient.
Do not weaken the deadline when queues become slow. Reduce admitted work, extend approval through a new accountable decision, or let the request expire.
Treat One-Shot Approval as Durable Workflow State
A field saying maximum_uses: 1 cannot prevent two workers from acting unless something enforces consumption.
Use a protected action ledger: durable records that track approval reservation, execution attempts, and unresolved effects. The following are proposed states, not Kubernetes resource statuses.
| State | Meaning | Constraint |
|---|---|---|
| Available | The approval may be claimed if its other conditions hold. | Claim must be concurrency-safe. |
| Claimed | One executor owns the current execution attempt. | Other workers cannot independently spend the same approval. |
| Dispatch prepared | Intent to cross the target boundary is durably recorded. | A crash may leave execution uncertain. |
| Verified or rejected | Required evidence supports the applicable conclusion. | Retain the decision and attempt history. |
| Unresolved | The record cannot establish what happened. | Do not automatically replenish the approval. |
Reservation and external execution are separate events unless the architecture supplies an appropriate transaction mechanism. Marking an approval consumed before dispatch can strand legitimate work after a crash. Marking it consumed afterward can leave a duplicate-execution window.
The remedy is explicit recovery behavior, not choosing whichever ordering makes the happy path simpler.
A Worker Timeout Must Not Create a Second Owner Automatically
An expired worker lease does not prove the original worker stopped. Reassigning its action without controlling the stale worker can create concurrent execution.
Define how stale executors are fenced from the target or how the target rejects the duplicate operation. A local lock that disappears on restart is not enough.
For this exact ConfigMap patch, the old starting-state conditions provide additional protection against repeating the same mutation after a successful update. That is narrower than a distributed exactly-once guarantee and does not replace the approval ledger.
Keep Retry Identity and Request Meaning Together
Amazon’s Making retries safe with idempotent APIs describes caller-provided request identifiers and rejecting changed parameters under an existing identifier. It also emphasizes service-dependent retention of that knowledge.
Apply the distinction here. A transport retry of the same action must preserve its meaning. A refreshed revision, changed target, or revised operation is not simply another transport attempt.
Kubernetes does not consume the builder’s action_id as an application approval or deduplication record. That field needs enforcement in the surrounding workflow.
Do Not Make an Approval Object Look Like a Transaction
Kubernetes ValidatingAdmissionPolicy supports parameter resources, which can supply governed values to validation expressions. That is useful for policy configuration.
However, referencing an approval-shaped object does not establish atomic consumption of that approval together with a separate ConfigMap update. It also does not independently prove who approved it or whether its state remains current across every relevant path.
For this companion, leave the fixed admission policy unchanged and put action-specific authority in the external execution design.
A later integration can move selected checks closer to admission, but it must preserve missing-parameter behavior, configuration ownership, state consistency, and failure semantics. Adding another Kubernetes object is not a substitute for defining those properties.
The direct executor credential remains a trust boundary too. Someone who controls it may bypass the external approval service while still satisfying the fixed admission invariant. Protect that credential, or implement an additional target-enforced approval mechanism where the threat model requires resistance to executor compromise.
Test the Conditional Patch Without Claiming a Complete Approval System
After the trusted operator has authorized the bounded lab change and recorded the required evidence, the following command exercises the native target preconditions:
kubectl --kubeconfig ../rtb-kubernetes-boundary-kit/credentials-02/executor.json -n rtb-boundary-lab patch configmap retention-fixture --type=json --field-manager=rtb-bound-action --patch-file candidate-02/patch.json
This direct command does not read the external approval record, enforce its deadline, consume its allowance, or compare the surrounding request manifest. It is a target-precondition test, not the production dispatch path.
Kubernetes’ kubectl patch documentation provides the JSON patch type and patch-file interface used here. Preserve the actual request and response when validating the chosen client.
Read the result through the observer and retain the same-object check:
kubectl --kubeconfig ../rtb-kubernetes-boundary-kit/credentials-02/observer.json -n rtb-boundary-lab get configmap retention-fixture -o json > evidence-02/after.json
For an unchanged, correctly bound target with all applicable controls satisfied, the expected result is forty-five on the reviewed UID. A mismatched UID, revision, or starting data must prevent that conditional request from changing the object.
These outcomes were not executed against a cluster for this article.
Make the Full Workflow Fail in Useful Ways
The application-level integration needs tests beyond patch construction.
| Challenge | Required result |
|---|---|
| Correct value, but no approval | External execution service denies or holds before dispatch. |
| Body, target, cluster, or executor changes after approval | Binding check rejects the substituted request. |
| Approval expires or is revoked while queued | New dispatch remains blocked. |
| Reviewed object changes or is recreated | Original request fails its applicable preconditions; no silent rebasing. |
| Two workers claim one approval | Only the permitted execution ownership is established. |
| Worker loses the reply after target commitment | Action remains attributable or unresolved, without an unsafe fresh attempt. |
| Old ledger backup is restored | Consumed approvals and current restrictions are not silently reset. |
| Observer cannot establish the result | Completion is not marked verified. |
Run permitted cases too. An unavailable approval service that blocks everything can establish a degraded condition, not a useful production workflow.
Separate tests of the external gate from tests of target preconditions. If a modified request is rejected by the approval binding, it has not exercised the target’s UID check. Record which boundary received the request and which one refused it.
For stale-state testing with this fixed admission policy, use controlled scenario preparation. Do not disable admission or grant the agent new reset privileges to manufacture a convenient test sequence.
Reconcile a Lost Reply Before Granting Another Attempt
Suppose the API call times out and the observer subsequently sees forty-five.
That observation supports the current setting. It does not necessarily establish which actor changed it. Another authorized writer may have performed the same transition.
Join the approved request, attempted transmission, target response or audit information, and independent observations. Preserve what each establishes and what remains unknown.
The execute, verify, and recover agent actions pattern provides the operational companion. Its central distinction remains important: a missing response, a failed operation, and an unsupported completion claim need different handling.
Do not recover by returning the live fixture to thirty through a control bypass. Preserve evidence and use the prior kit’s controlled teardown and reconstruction for a fresh experiment. In a real service, a compensating change would require current authorization and checks against legitimate concurrent work.
A verified correction also does not erase historical effects. This ConfigMap is inert; a real retention service would require separate analysis of recovery points and any consequences of the earlier setting.
Operate the Approval Service as a Control Dependency
The approval service, ledger, clock, registry, and executor release path become part of the action’s availability model.
Assign owners for their integrity, capacity, access, recovery, and escalation. Expired approvals can indicate slow review or overloaded dispatch, while excessive revision conflicts can indicate a mismatch between the chosen preconditions and the workload’s change rate.
Repair those operating problems without hiding them. Track queue age, stale-proposal frequency, unresolved attempts, and time until suspension blocks new dispatch.
Protect recovery against old authority. Restoring the executor or ledger should begin with dispatch disabled until current revocations, consumed actions, and pending attempts have been reconciled.
Start with one action class. Validate request binding and native preconditions, then implement the approval and ledger path in an isolated integration environment. Only the demonstrated operating scope should proceed to bounded production use.
Conclusion
A valid Kubernetes change can still be unauthorized. The value may satisfy admission while the request targets a different object, uses stale approval, or spends the same authority twice.
Bind the approval to the actual request and its relevant starting state. Preserve that binding through execution. Keep expiry, consumption, uncertainty, and recovery in independently governed control services rather than fields the agent can assert.
The request builder makes one part of that design inspectable. Its local tests establish construction behavior, while current authority, distributed execution, and target observations still require their own evidence.
The control plane must not grade itself.
Approve one bounded change, then alter its target state before dispatch. Does the system ask for a new decision, or quietly rewrite the request until the old approval works?
Continue the practical companions
This practical companion extends The Recursive Trust Benchmark. Start with the Independent AI Assurance series or explore the Enterprise AI hub.
- Previous companion: From Simulation to Kubernetes: Testing Agent Identity and Admission
- Next companion: Building an AI Agent Execution Ledger That Survives Restarts
External References
- OWASP: Transaction Authorization Cheat Sheet
- Kubernetes: Object Names and IDs
- Kubernetes: Kubernetes API Concepts
- IETF: RFC 6902, JavaScript Object Notation (JSON) Patch
- Kubernetes: kubectl patch
- Kubernetes: Validating Admission Policy
- Amazon Builders’ Library: Making retries safe with idempotent APIs
Move from an offline simulation to a disposable Kubernetes cluster. Test separate agent, executor, and observer identities, resource-scoped permissions, admission rules, and…
The post Binding AI Agent Approvals to Kubernetes Changes appeared first on Digital Thought Disruption.
