An agent has no password, no MFA, and nobody at the keyboard when it acts. Every control that assumes a human is present fails silently. This is what replaces them: five layers, each answering one question, each independently switchable.
core/workload_identity · core/agent_tokens · core/identity_resolution · core/delegation · core/capabilities
Read bottom-up. A layer is only meaningful if the one below it holds: a capability scoped to an agent means nothing if the agent principal was self-asserted.
Human credentials last a workday because a human is slow. Agent credentials should last one action, because the agent is not. Short lifetime is what replaces the revocation you cannot deliver in time.
| Credential | Default | Hard cap | Scope | Revocation |
|---|---|---|---|---|
| Workload credential | issuer-set | issuer-set | the process | the attestor's own rotation |
| Agent token | 10 min | 15 min | agent + instance + session | by instance, by jti, by user |
| Capability | 30 s | 60 s | one tool, one resource | nonce burned on first use |
| Control | Env | Default | What the default means |
|---|---|---|---|
| Workload providers | SHIELD_WORKLOAD_IDENTITY_PROVIDERS | admin_key,spiffe | oidc_sa and mtls are not enabled. An OIDC token
is ignored entirely until you add it. |
| Role binding | SHIELD_ROLE_BINDING | off | The role comes from the X-User-Role header, chosen by
the caller RBAC is constraining. prefer lets a signed claim win. |
| Token binding | SHIELD_TOKEN_BINDING | off | Tokens are bearer. Whoever holds one is the agent. |
| Delegation | SHIELD_DELEGATION | off | No user is bound to the action; the agent acts on its own authority. |
Every one of these defaults fails open and quiet. Send a perfectly valid
Keycloak token to a Shield whose provider list is the default and nothing rejects it.
the token is simply never read, and the header is used instead. The request succeeds.
The audit record says the role was header-sourced, and that is the only
place the difference is visible.
So the deployment check is not "does a valid token work". It is does an invalid one fail. Present a forged role alongside a signed token and confirm the signed claim wins.
| # | Step | Why this order |
|---|---|---|
| 1 | Enable the workload provider you actually use
(oidc_sa for Keycloak or K8s, spiffe for a mesh) |
Nothing above L0 can be verified until something at L0 is. This alone changes no decision, so it is safe to ship first. |
| 2 | Set SHIELD_ROLE_BINDING=prefer |
Signed claims start winning over headers. prefer falls back
to the header when no claim exists, so unmigrated callers keep working. |
| 3 | Watch role_source in the audit log |
Every caller still reading header is one that has not
migrated. This is the list you need before step 4. |
| 4 | strict / required |
Unverified claims are now refused. Safe only once step 3 is empty. |
Verify a live deployment with examples/langchain/verify_deployment.py, it reports role provenance and exits non-zero when a layer is not actually enforcing.