Radia is not a secret store and does not replace one. It changes which processes need a secret at all: callers hold an identity, a few narrow workers hold the dangerous credentials, and authority becomes permission to request an operation rather than possession of a token. This guide shows how to make that change incrementally, and what it costs.
In most deployments a secret manager provisions a downstream credential to every process that needs the system behind it. Each process is then trusted with whatever that credential can do, and compromise of the process is compromise of the credential.
The target is not fewer secrets. It is fewer holders, and a different way for application code to express authority.
Nothing below requires a rewrite. Each transition is independently useful and can leave the previous path working while it is evaluated. Stop where the next boundary does not justify its operational or data cost.
Start with one survivable path and one external operation. Do not begin with a production administrative credential merely because it has the largest theoretical payoff.
Name one credential, every process that can retrieve it and the concrete operations each caller actually needs.
Define one request kind and one result kind. Declare every field that must participate in routing or authorization as an indexed path.
Choose retention before request bodies enter the space. Decide which fields may remain visible to matching, operators and observers.
Confirm that the downstream operation accepts an idempotency key or has another durable deduplication mechanism.
Deploy Radia next to the current architecture and change no existing credential. Selected processes gain a Radia identity as an additional interface.
The process exchanges its durable bootstrap credential for a short-lived run token. The durable credential can mint runs but cannot perform ordinary operations, so it is never the acting credential. Still, minting is a single call, so a leaked bootstrap credential is one hop from the agent's full authority. What the split buys is a short-lived acting credential, one minting handle to revoke, and a record of every mint.
At this point no downstream credential has been removed, so containment has not improved. What Radia establishes is the foundation later transitions need: principals, record kinds and their indexed paths, grants, and the claim and lease behaviour your workers will rely on. Decide where the bootstrap credential comes from now rather than later.
Take one service that holds a credential and give it a second way to be asked. The existing HTTP path stays exactly as it is.
The service still reads ERP_TOKEN from Vault. The selected caller uses the record
path but retains its token for rollback during evaluation. Removing it is the next transition.
A legacy system does not have to learn anything. A bridge worker translates a record into whatever the system already speaks, which is how Radia spreads from the edges inward rather than from a rewrite.
A bridge worker claims one operation, calls the existing system and writes a result record. A failed call is an answer, not a refusal to settle: a downstream rejection that nacks the claim is redelivered, while a failure result becomes one durable record that consumers handle with the normal delivery semantics. See the worked examples →
After this transition, compromise of the caller yields only what its grants permit, not the ERP token.
customer-reader,
invoice-writer, deploy-worker. The runtime, its storage and any
credential-holding host stay trusted components, so the goal is to reduce their number and
authority rather than to assume Radia makes them harmless.
A secret-manager policy answers one question: may this workload retrieve this credential. Retrieval then implies everything that credential can do.
A grant names a principal, a concrete kind and the operations allowed on it. Wildcard kinds are refused, so authority is enumerated rather than implied. Grant changes remain visible in the record history.
{ "principal": "agent:invoice-agent",
"kind": "erp.invoice.create",
"operations": ["put"] }
Advertising a capability is not authorization. A worker may publish what it handles, and only an operator or authorized supervisor can write the grant that permits it. See how grants are enforced →
The database worker holds one credential that can read every tenant. Without scoping, each caller's code is what keeps tenants apart, which means every caller is part of the security boundary.
{ "principal": "agent:acme-assistant",
"kind": "customer.query",
"operations": ["put"],
"pattern": { "tenant": "acme" } }
A pattern bounds both reads and writes. A broad read is narrowed to permitted content, and a write outside the pattern is refused before a worker receives it.
tenant is the isolation boundary, declare it when the kind is
created rather than burying it inside an opaque payload.
What each principal can actually do is a read rather than a belief:
radia permissions agent:acme-assistant answers from the same path the enforcement
uses. See effective permissions →
A shared worker serving many callers is the point where a broker usually becomes a way to borrow the worker's authority. Radia's answer is a delegated run whose authority is the intersection of the caller's grants and the worker's.
The worker uses its own run for its own work and a delegated run for work performed on a caller's behalf. Radia derives that caller from the authenticated run, not from a claim in the request body.
A container that holds cloud keys, a source-control token, a database URL and model-written Python is the combination this transition exists to end.
Generated code receives a narrow proposal interface rather than a credential. The trusted host supplies identity and provenance, then Radia applies the agent's ordinary grants. This is stronger than injecting a short-lived token because the sandbox has nothing to steal or replay. See credentialless execution →
The built bootstrap chain keeps a durable credential in the secret manager and is available on any deployment.
Store the durable definition credential like any other infrastructure secret and expose it only to the trusted host, as a file with restrictive permissions rather than an environment variable, which tends to reach diagnostics, crash dumps and deployment manifests. The host exchanges it for renewable, short-lived runs rather than using it for application work.
Radia can also mint a run from a verified OIDC identity, resolving the principal through an explicit mapping. A compatible workload-identity platform can therefore avoid storing a durable Radia credential. The space has to be started with the issuer and the audience it accepts, and that audience is a single value per space, so one space accepts tokens minted for one audience. Ready-made Kubernetes and SPIFFE profiles are not shipped today, so treat this as an integration to validate, not a turnkey deployment path.
radia runs --for <principal>
--stop), and it covers both the principal's own runs and delegated runs held by
workers on its behalf. An incident response does both.
Give each environment its own principal and its own stored credential. Compromise of development should not yield a minting credential for production, and separate spaces are a stronger boundary than separate grants inside one space.
Delivery is at-least-once. A worker can perform an external effect and fail before its settle lands, after which the work is redelivered. Any bridge worker that charges a card, sends mail or files a document needs deduplication at the external boundary, designed in from the first one rather than added after the first duplicate.
Moving credentials out of callers also moves request data into a shared store. Price that trade before adding the record path, not after relying on it.
| Concern | Who owns it |
|---|---|
| Grant intersection, lease fencing and write authorization | Radia enforces |
| Storage and rotation of the downstream credential | Secret manager and capability-worker host |
| External API deduplication | Capability worker and downstream system |
| Sandbox isolation | Selected backend and trusted host |
| Request-body retention and routable plaintext fields | Application and kind design |
| TLS, request limits, backup and shared deployment storage | Deployment infrastructure |
Record bodies are stored as plaintext JSON, not only the fields that route: matching needs the routed ones, and the rest sit beside them. Operators and principals with observation authority can read those bodies, so sensitive payloads and retention need deliberate design. Application-level encryption is available for fields that do not participate in routing.
Records are immutable and remain unless the writer or kind declares retention. Large or erasable content belongs in artifacts rather than record bodies.
Claiming, leasing and settling add more work than a direct HTTP call, and several runtime instances need shared storage. Radia has not yet established production readiness through independent adoption. Pilot it on a real but survivable path rather than replacing a mature authorization boundary at once. See what it is not →
Start with credentials whose risk justifies a new boundary, while keeping the first path survivable. The worst combination is broad authority, many holders, agent-controlled code and a high-value target; the best first pilot is often one step below it.
The objective is not zero credentials. It is that very few processes hold one that can act on an external system, and that possession stops being how application code expresses authority. Two numbers say whether that is happening.
A production database credential reachable by thirty-seven workloads today, and by three capability workers after the first transitions, is a real result even if the secret manager never moves.