Skip to main content

Stop Handing Agents Immortal Keys: Short-Lived Sandbox Credentials with Kubernetes 1.37 Pod Certificates

9 min readDora NodaDora Noda
Share
On this page

Every credential you mount into an AI-agent sandbox is one prompt-injection away from being pasted into a log, a tool call, or a chat transcript. With a bearer token, that paste is the whole identity: whoever holds the string is the workload until the token expires. Time, audience, and object bindings narrow the window, but inside the window the thief is you.

Kubernetes 1.37 "Garhwal," released August 26, 2026, graduates the structural fix to stable: Pod Certificates and Cluster Trust Bundles. Instead of a copyable string, each sandbox gets a short-lived X.509 client certificate whose private key is generated on its own node and never leaves it. A leaked certificate without the key is useless, rotation happens without restarting the pod, and every issuance leaves an API record. Here is the concrete design for a sandbox credential that calls a deploy API, the migration checklist off long-lived service-account secrets, and the audit evidence to collect before agent-issued deploys become routine.

The design first: a sandbox credential in one pod spec

Picture a multi-tenant fleet on Cluster API: each tenant's agent sandboxes run in their own namespace, on nodes the platform owns, and sandboxes need exactly one privileged thing — calling the deploy API to ship what the agent built. That credential must be narrowly scoped to the tenant, short-lived, rotatable without a restart, and worthless once leaked or expired. This is the pod spec that delivers it:

yaml
volumes:
  - name: deploy-identity
    projected:
      sources:
        - podCertificate:
            signerName: sandbox.example.com/deploy-identity
            keyType: Ed25519
            maxExpirationSeconds: 3600
            credentialBundlePath: credential.bundle.pem
  - name: deploy-api-trust
    projected:
      sources:
        - clusterTrustBundle:
            signerName: sandbox.example.com/deploy-api-serving
            path: trust-anchors.pem

Three scope-narrowing mechanisms work together here, and the certificate alone is only the first. The signer mints a SPIFFE-style identity encoding the pod's namespace and service account, so the credential is bound to one tenant's sandbox rather than a shared platform account. The signer controller verifies each request against the pod and service-account identity before issuing, refusing anything addressed to an identity the requester does not own.

And the deploy API maps the presented SPIFFE ID to a tenant allowlist, so even a valid certificate from tenant A cannot deploy tenant B's app. Kubernetes' own RBAC adds a fourth rail: a pod author needs the use verb on that exact signers resource before kubelet will even request a certificate from it.

The lifetime story is what makes theft boring. The signer answers each request with a beginRefreshAt timestamp, kubelet re-issues ahead of expiry and rewrites the single-file credential bundle, and the sandbox agent reloads it via inotify or polling — no pod restart, no redeploy, no orchestrator involvement. Core signers, when they ship, will cap lifetimes at 24 hours; third-party signers face a 91-day ceiling that is a guardrail, not a target. Set maxExpirationSeconds to an hour and a token stolen from a transcript dies within the hour — and unlike a bearer token, it was never replayable in the first place, because the private key it needs never left the node.

Static SA secret (before)Pod certificate (after)
Theft valueFull identity: replayable anywhere until expiryUseless without the node's private key
LifetimeNever expires unless rotated by handShort (e.g. 1h), auto-refreshed via beginRefreshAt
RotationManual secret rotation plus pod restartAutomatic, no restart; app reloads one file
ScopeEvery power the service account holdsSPIFFE ID + signer policy + API-side tenant mapping
Audit recordSecret mount leaves no issuance trailEach issuance is a PodCertificateRequest API object

One honest caveat before the migration plan: bound projected service-account tokens — the default since 1.21, one-hour TTL, refreshed at 80 percent of lifetime, invalidated when the pod dies — already beat legacy secrets on every row except theft value. Pod certificates beat bound tokens specifically on proof-of-possession. If your fleet still mounts secret-backed tokens, moving to projected volumes is step one whether or not you adopt certificates next.

How issuance works: six steps from pod spec to mTLS

The mechanism, described by SIG Auth's Taahir Ahmed in the August 28 Kubernetes blog post, mirrors service-account JWT issuance deliberately — the goal was making X.509 "just as easy as using service account JWTs." Three components participate: your application, kubelet, and a signer controller.

  1. Once the sandbox pod lands on a node, kubelet finds the podCertificate and clusterTrustBundle projected volume sources in its spec.
  2. For each certificate source, kubelet generates a fresh private key per keyType, creates a PodCertificateRequest addressed to the signer, and — once the signer fills in status.certificateChain and status.beginRefreshAt — writes the key and chain to the container filesystem.
  3. For each trust-bundle source, kubelet unifies every matching ClusterTrustBundle, stably reorders the anchors so applications cannot depend on ordering, and writes them to the named path.
  4. The pod starts; the agent reads its identity and trust anchors from the filesystem.
  5. Kubelet keeps trust-bundle files current as the selected bundles change.
  6. Past each beginRefreshAt, kubelet re-issues and rewrites the files; the application picks up the change via inotify or polling.

Security checks live in kube-apiserver rather than in each signer. Node restriction means a compromised node can only request certificates for pods actually scheduled to it — it cannot mint identities for the rest of the fleet. That property matters doubly on a multi-tenant platform: one tenant's breached node cannot escalate into another tenant's sandbox identities.

Migration checklist: off long-lived service-account secrets

Most fleets reaching for this feature have the same starting point: sandboxes mounting secret-backed tokens that never expire, scoped to service accounts with more power than any single agent task needs. Migrate in this order:

  1. Inventory every long-lived token. List secret-backed service-account tokens mounted into sandbox namespaces. Anything with no expiry is the migration backlog; rank by privilege, widest first.
  2. Move to projected TokenRequest volumes where certificates are not ready yet. Bound, audience-scoped, one-hour tokens are strictly better than immortal secrets and require no signer. This step alone closes the "leaked token works forever" hole.
  3. Deploy or adopt a signer controller. No signer ships in core Kubernetes yet — the reference starting point is Tinycert, explicitly a toy, with a service-DNS signer, a SPIFFE-compatible signer, and a Go helper library. Production means building on it or adopting a vendor signer, plus granting it update on podcertificaterequests and sign on its signers resource.
  4. Gate issuance with RBAC. Grant sandbox service accounts use on only the deploy-identity signer, per tenant namespace. A pod author who cannot use the signer cannot get its certificates — scope enforcement starts before issuance, not at the API.
  5. Make the agent reload on rotation. Subscribe to the credential bundle file and reload the TLS client on change. The single-file bundle exists precisely so rotation is one atomic read; split key/cert files reintroduce mid-rotation races.
  6. Set the lifetime policy, then dual-run and revoke. Cap sandbox certificates at an hour, run certificates alongside tokens during the cutover, then delete the legacy secrets and confirm nothing breaks. Revocation is deletion: no CRL to maintain when nothing long-lived remains.

Audit evidence before agent-issued deploys go routine

"Let the agent deploy" is the moment sandbox credentials stop being an experiment and start being infrastructure. Collect four pieces of evidence first:

  • Issuance records. Every certificate comes from a PodCertificateRequest object naming the pod, signer, and key type. Retain them as the who-got-what ledger; a credential with no request object is a finding, not a feature.
  • API audit trail. Issuance, refresh, and signer decisions flow through the apiserver, so the existing audit log covers the credential lifecycle with no new pipeline. Verify the events you expect actually appear before you depend on them.
  • Signer authorization proof. Show the RBAC grants (use for requesters, sign for the controller) and node-restriction enforcement in a staging breach drill: a compromised node requesting another pod's identity must fail closed.
  • Blast-radius math. Document the worst case in numbers: a one-hour, proof-of-possession, tenant-scoped credential versus the immortal bearer token it replaced. When the postmortem asks "how long was the stolen credential valid," the answer should be a TTL, not an investigation.

The industry consensus has converged here independently of Kubernetes: broker narrowly scoped, short-lived credentials into the sandbox at task time, keep long-lived secrets outside it, and log every agent action so "the agent did it" is the start of the audit trail rather than the end of it.

Honest limits: what still needs building

Pod Certificates reached GA as machinery, not as a turnkey product. No signer ships in core Kubernetes — the project expects at least two eventually (service-DNS server certificates and SPIFFE client certificates), but today you build or borrow one. Applications must handle rotation; a client that reads its certificate once at startup will break at the first refresh, loudly and at the worst hour. The SPIFFE Filesystem Delivery draft standard aims to make consumption uniform, but it is still a draft. And the 91-day third-party ceiling is a maximum, not guidance — anything near it in a sandbox deserves a written justification.

None of this blocks adoption; it scopes it. The teams that benefit first are the ones already running multi-tenant sandbox fleets with a signer they control and agents that reload credentials — exactly the operators for whom static secrets are already a known liability.

Short-lived identity is the default your agents deserve

The arc of Kubernetes workload identity points one way: from immortal secret tokens, to bound one-hour JWTs, to proof-of-possession certificates that die young and rotate silently. Version 1.37 makes the third stage a platform API instead of glue you maintain. For agent sandboxes — the workloads most likely to leak whatever they hold — that is not a nice-to-have. It is the difference between a leaked credential being an incident and being a non-event.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with AI agents as first-class operators. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex