The last mile: from zero trust tokens to real-world resources

by | Jun 24, 2026 | AI

Key takeaways: The last mile problem is translating a verified zero trust delegation token into credentials that external resources will accept while preserving the permission intersection. This is solved by a credential gateway that validates the token, computes the permission intersection, and translates it into short-lived, service-specific credentials.

In Parts 1 and 2 of this series on implementing zero trust for AI agents on RedHat OpenShift, we built a complete zero trust identity flow: delegation with permission intersection, traceable through nested JWT act claims, authenticated by SPIFFE and token exchange. Every hop is verified, every agent is scoped.

But here’s what kept nagging me during development: all of this works because we control both sides of the conversation. The document-service is our code—it validates our JWTs, queries our policy engine, and enforces our permission model. Real-world agents don’t just talk to services we wrote. They need to read files from S3, fetch code from GitHub, post messages to Slack, query databases. Each of these services has its own authentication mechanism, its own credential format, and its own permission model.

This is the last mile problem: translating a verified zero trust delegation token into credentials that an external service will actually accept, while also preserving the permission intersection.

The credential gateway

The solution is a credential gateway—a service that sits between your zero trust identity layer and external resources. It does three things:

  1. Validates the incoming JWT and extracts the delegation chain from nested act claims
  2. Queries the policy engine to compute the permission intersection for the specific target service
  3. Translates the intersection into service-specific credentials via backend adapters
JWT with          ┌─────────────────────────────┐        Service-specific
act claims ──────►│     Credential Gateway      │──────► credentials
                  │                             │
                  │  Validate → OPA → Adapter   │
                  └──────────────┬──────────────┘
                                 │
                    ┌────────────┼────────────┐
                    ▼            ▼            ▼
                 AWS STS     GitHub App    Vault/OpenBao
                (session     (scoped       (dynamic DB,
                 policy)     install       SSH certs)
                             token)

The gateway is the only component that holds master credentials (IAM role ARNs, GitHub App keys, database root passwords). Agents never see these—they receive short-lived, scoped credentials that enforce the permission intersection.

What makes this pattern work is that the gateway reuses the infrastructure we already built. JWT validation is the same as in the document service. The OPA query is the same policy engine, extended with service-specific rules. The delegation chain extraction is the same act claim parsing. The only new piece is the adapter that translates the intersection into credentials the target service accepts.

AWS S3: where permission intersection is native

We picked S3 as the first credential gateway target for a specific reason: AWS STS session policies already implement permission intersection natively.

When you call AssumeRole with a session policy, AWS computes:

Effective permissions = IAM role policy ∩ Session policy

This is exactly our model. If the IAM role grants access to finance/* and engineering/*, and the session policy (computed from the agent intersection) only allows engineering/*, the STS session can only access engineering/*. AWS enforces this—not our code.

Here’s the concrete flow when Alice delegates to summarizer-tech to read from S3:

  1. The agent presents Alice’s delegated JWT to the credential gateway.
  2. The gateway extracts the chain: Alice → summarizer-tech.
  3. OPA computes the intersection: Alice’s departments [engineering, finance] ∩ summarizer-tech‘s capabilities [finance, engineering] → [engineering, finance].
  4. The gateway calls STS AssumeRole with an inline session policy scoped to the intersection—only s3://data/engineering/* and s3://data/finance/*.
  5. The agent receives temporary AWS credentials (access key, secret key, session token) valid for a short window (15 minutes in our demo, configurable up to 12 hours via STS).
  6. The agent uses these credentials to access S3—any attempt to read outside the scoped prefixes gets an AccessDenied from AWS itself.

Now consider Carol delegating to summarizer-tech. Carol has [hr], the agent has [finance, engineering]. The intersection is empty—the gateway returns a 403 before ever calling STS. No credentials are issued.

The beauty of this approach is that even if something goes wrong in our code, AWS is the backstop. The session policy is evaluated by AWS on every S3 request. A bug in our gateway can’t grant more access than the session policy allows.

The pattern repeats, the adapters change

S3 was the first step, but the credential gateway architecture is designed to support multiple backends. The pattern is always the same: validate JWT, compute intersection, translate to credentials. Only the adapter changes.

Each service type has a natural fit:

Target serviceCredential mechanismHow intersection is enforced
AWS S3STS session policyNatively by AWS (implemented)
GitHubApp installation tokenScoped to repository subset
PostgreSQLDynamic user via Vault/OpenBaoRestricted SQL GRANT privileges on specific tables
SSHSigned certificateLimited principals and hosts
SlackProxy-based filteringGateway filters API calls

Some of these are cleaner than others. GitHub App installation tokens can be scoped to specific repositories—a direct translation of the permission intersection. Databases can get dynamic, short-lived users with restricted grants, ideally through OpenBao (the open source fork of HashiCorp Vault) which has built-in secrets engines for this. For services like Slack that don’t support fine-grained credential scoping, the gateway acts as a filtering proxy—intercepting API calls and blocking those outside the intersection.

We’re also watching Biscuit tokens as a longer-term option. Biscuit supports attenuation: any token holder can add restrictions but never expand permissions. This maps directly to delegation chains: each hop attenuates the token further, and the permission intersection is cryptographically enforced in the token itself. Adoption is early, but the model is a natural fit.

The key insight from building the S3 adapter: look for services where the permission intersection can be enforced by the target system, not just by your gateway. AWS does this with session policies. The more you can push enforcement to the target, the smaller your trust surface.

Wrapping up the series

The last mile is where zero trust meets the real world. Token exchange gives you verified identity with delegation context. The credential gateway translates that into something each external service understands while preserving the permission intersection that keeps agents scoped to least privilege.

The architectural bet is straightforward: one gateway, one policy engine, many adapters. Start with the services where intersection enforcement is native (like AWS STS), then work outward to services that need proxy-based filtering or dynamic credential generation.

Looking back across all three posts, the pieces compose into a consistent model:

  • Part 1 established the principle: agents reduce permissions, never expand them. The permission intersection pattern makes this structural, not aspirational.
  • Part 2 wired the identity plumbing: SPIFFE for workload identity, token exchange for delegation context, Kagenti for agent lifecycle. All standards based, all composable.
  • Part 3 tackled the last mile: translating zero trust delegation tokens into real-world credentials, starting with AWS S3, where the intersection is enforced natively.

None of these pieces required inventing new protocols or building custom identity systems. SPIFFE, RFC 8693, OPA, STS session policies—they all existed. The work was in composing them into a coherent system where AI agents can operate safely under delegation, with every permission traceable and every credential scoped.

As we add more credential adapters—GitHub, databases, service meshes—we’ll share what we learn.

This post is part of a series on implementing zero trust for AI agents on OpenShift:

More documentation is available in our zero trust agent demo on GitHub.