Skip to main content

Workload identity for AI

AI agents, pipelines, and MCP server callers are multiplying fast. Each one needs an identity. The question is whether that identity is a stored secret someone can steal — or something the platform itself guarantees.

The identity problem in AI

Every AI workload that calls an MCP server needs to answer one question: "Who are you?"

Traditional answers break down at scale:

ApproachWorks until...
Hardcoded API keySomeone commits it to git, or it leaks in a log
Shared service account secretTwo teams share a secret; audit can't tell who called what
Per-workload secret in env varsYou're managing hundreds of secrets across dozens of clusters
Private key on diskA container image rebuild ships the key to every environment

The pattern: every stored credential is a liability. It can be copied, shared, leaked, forgotten, or used by something other than the intended workload. And the more AI workloads you run, the worse it gets.

What workload identity changes

Workload identity flips the model: instead of giving a workload a credential it holds, you let the platform prove what the workload is.

Traditional (stored credential)Workload identity (SPIFFE)
The workload says"Here's my secret""I'm this pod, in this namespace, running this service account"
What happensAnyone with the secret is the workloadThe platform attests the pod's runtime attributes
ResultLong-lived credential that can be stolenShort-lived token issued on demand — nothing to steal

The difference is fundamental:

Stored credentialWorkload identity (SPIFFE)
Identity sourceSomething you know (a secret)Something you are (runtime attributes)
Can be stolen?Yes — it's a stringNo — there's nothing to copy
Shared across pods?Often, yesNever — each pod has its own SVID
RotationManual deploymentAutomatic every ~5 minutes
Audit trail"A caller with secret X""Pod Y in namespace Z with service account W"
Survives container restart?Only if re-injectedYes — SPIRE re-attests automatically

How SPIFFE works

SPIFFE (Secure Production Identity Framework For Everyone) is the open standard behind workload identity. SPIRE is the runtime that implements it.

The three actors

  1. Your pod asks the local SPIRE agent for a JWT-SVID (via unix socket)
  2. SPIRE agent checks the pod's runtime attributes (namespace, service account, labels, image) against registered selectors
  3. If the attributes match, SPIRE issues a JWT-SVID — a signed, short-lived token containing the workload's SPIFFE ID

The SVID

A JWT-SVID looks like any JWT, but its claims are platform-attested:

{
"sub": "spiffe://acme.prod/ns/ml/sa/inference-pipeline",
"aud": ["https://app.authsec.ai/oauth/token"],
"exp": 1719500000,
"iat": 1719499700
}
  • sub — the SPIFFE ID, uniquely identifying this workload
  • aud — what this SVID can be presented to (AuthSec's token endpoint)
  • exp — expires in ~5 minutes; SPIRE auto-renews before expiry

No secret, no key, no password. The SVID's authority comes from SPIRE's attestation of the pod's runtime identity.

SPIFFE's role in the AI identity landscape

AI workloads come in three flavors. Each needs a different identity model:

1. Machine callers (pipelines, batch jobs, services)

These call MCP servers as themselves with standing permissions. SPIFFE is the strongest option:

No stored secret anywhere in the chain. The pipeline's identity is its Kubernetes identity.

2. AI agents acting for users (ID-JAG)

These act on behalf of a signed-in user. SPIFFE authenticates the agent itself; the user's identity comes from the OAuth login:

SPIFFE answers "which agent is this?" while ID-JAG answers "acting for whom?" — they're complementary, not alternatives.

3. Interactive MCP clients (Claude Desktop, Cursor)

These run on a user's machine, not in Kubernetes. SPIFFE doesn't apply — they use OAuth DCR and the user's own login. No workload identity needed.

Where each fits

Workload typeIdentity methodSPIFFE role
K8s pipeline / batch jobSPIFFE SVID → OAuth tokenPrimary identity
K8s service calling MCPSPIFFE SVID → OAuth tokenPrimary identity
AI agent (K8s) for usersSPIFFE + ID-JAGAgent identity (user identity via OAuth)
AI agent (non-K8s) for usersClient secret/JWT + ID-JAGNot used
Interactive client (desktop)OAuth DCRNot used
CI/CD pipeline (GitHub Actions)OIDC federationSimilar pattern (platform-attested)

SPIFFE vs other identity approaches

vs API keys / client secrets

API keys are shared strings. Anyone who has the key is the caller. SPIFFE binds identity to the workload's runtime — nothing to share, nothing to steal.

vs private-key JWT (RFC 7523)

Private-key JWT is better than secrets (the key never crosses the wire), but the key file is still stored on disk. SPIFFE eliminates stored credentials entirely — the "key" is the pod's Kubernetes identity.

vs Kubernetes service account tokens

K8s service account tokens prove "I'm in this namespace with this service account" — similar to SPIFFE. But K8s tokens are bound to the cluster's API server; SPIFFE IDs are portable across clusters, clouds, and on-prem. SPIRE also adds richer attestation (pod labels, image hash).

vs cloud IAM (AWS IAM roles, GCP Workload Identity)

Cloud IAM is workload identity for one cloud. SPIFFE is workload identity across clouds. If you run in a single cloud, either works. If you run multi-cloud or hybrid, SPIFFE gives you one identity model everywhere.

Getting started with SPIFFE in AuthSec

Three steps, each done once:

  1. Deploy SPIRE in your cluster (quickstart)
  2. Register the trust domain in AuthSec (dashboard → Trusted Issuers → Add provider)
  3. Connect workloads per application (Access tab → Add access → Kubernetes workload)

Then your pods authenticate with zero stored credentials — forever.

→ Connect a Kubernetes workload (step-by-step)

Further reading