tl;dr — An agent under Vijil Dome carries a SPIFFE identity: a URI naming the agent, backed by an X.509 certificate that the platform issues from verified facts about where the workload runs. No secret is configured, none is shared, and nothing lives longer than an hour. The proxy re-verifies that identity on every request before it releases any credential to act. This post walks the full mechanism: how the identity is issued, how it is proved, what the proof buys, and how to turn it on.
An AI agent must carry a verifiable identity before anything else about it can be trusted. Sounds good. But how exactly does an agent prove who it is?
Why agents have an identity problem
A principal cannot delegate an objective to an agent that has no identity of its own. You cannot trust what you cannot name. You cannot trace workflows, grant or revoke authorizations, monitor agent behavior, audit operations, evaluate outcomes, or attribute credit and blame. In short, you cannot operate a business with anonymous agents for very long.
Agents are harder to identify than ordinary software applications. They act with delegated authority, they have unpredictable behavior (which is both a feature and a bug), and they are increasingly connected and consequential. They have access to models, tools, data stores, and other agents. An anonymous process with that scope is not a trust problem waiting to happen. It is one already.
How agents get credentials today
The common answers borrow identity for agents from somewhere else.
One convention extends IAM: the agent runs with a human's credentials. Now the agent holds every permission that person holds, and when it misbehaves, the audit trail blames a person who was not in the room. The identity is real. It just belongs to someone else. The pattern is formalized in OAuth token exchange (RFC 8693), whose act claim exists to say that one party acts on behalf of another. The delegation is honest but the identity still is not the agent's own. And a credential's role verifies nothing about the agent that holds it: any binary with the right role gets the permissions, and a tampered one keeps them.
A second convention mints proprietary non-human identity: a vendor-specific format that identifies your agents inside one vendor's walls. It works until you have two identity providers. Your agent's identity is only as portable as your contract. The category is real enough to carry its own risk list, OWASP's Non-Human Identities Top 10: secret leakage, long-lived secrets, overprivileged identities. Its final entry, Human Use of NHI, is the first convention seen in a mirror.
The most common answer is neither. It is an API key to a model provider in an environment variable. A key is not an identity; it is a bearer token, and whoever holds it becomes it. Keys leak, outlive their owners, and say nothing about the thing that presents them. This happened. In March 2026, a supply-chain compromise reached LiteLLM, a widely used open-source LLM proxy: two poisoned package releases harvested credentials from environment variables (cloud keys, provider keys, CI tokens) at more than 2,500 organizations. Each stolen key granted its full authority to whoever held it. That incident is part of our mechanism's origin story: the design work below began in its wake.
None of this argues that workload identity is new. The gap is that agents inherit credentials and authority without an independently attestable identity of their own, one that can serve as the security subject across models, tools, policy, audit, and lifecycle. That is the gap we close.
The bet we made instead
We bet on an open standard. SPIFFE was proposed by Joe Beda at GlueCon in 2016 (he tells the story in “10 Years of SPIFFE”). Its reference implementation, SPIRE, was built by the team at Scytale, donated to the CNCF in 2018, and carried forward into HPE. In 2022 the projects graduated from the CNCF, the foundation that stewards Kubernetes, with adopters like Bloomberg, ByteDance, and Pinterest.
An agent that proves its identity with SPIFFE/SPIRE presents a credential the rest of the cloud-native world already knows how to verify.
We did not invent the passport. We make sure every agent carries one.
How exactly it works
The Vijil platform attests where the agent runs, binds the agent's identity to those verified attributes, and associates that identity with the declarations in the agent card (purpose, role, tools, delegates). It then issues a passport that expires in an hour. The passport is an X.509 certificate called an SVID (a SPIFFE Verifiable Identity Document). The agent ID inside the passport is a URI such as spiffe://vijil.ai/org/<team>/agent/<agent-id>.
The structure of that URI is the same for every identity in the trust domain, and that is what makes it useful for authorization. A policy that names a full URI matches one agent. A policy that names the prefix spiffe://vijil.ai/org/<team-id>/ matches every agent that team runs. A policy that names a namespace prefix matches every agent in the namespace. Plain pattern matching over a fixed path does the work; no separate policy language is needed. The structure is only as trustworthy as the names inside it, so identifiers are validated before any URI is built.
Enrollment is declarative. In a Kubernetes deployment, one label on the agent's pod opts it into the trust runtime, and a template turns platform facts into its identity:
kind: ClusterSPIFFEID
spec:
spiffeIDTemplate: "spiffe://vijil.ai/ns/{{ .PodMeta.Namespace }}/agent/{{ .PodSpec.ServiceAccountName }}"
podSelector:
matchLabels:
vijil.ai/trust-runtime: "enabled"The issuance of the identity depends on two checks. The Vijil-hosted SPIRE server first attests the node itself, using Kubernetes projected service-account tokens. The SPIRE client on that node then attests the agent: which namespace it runs in, which service account it runs as. Only when both checks pass does the agent receive its SVID. In Kubernetes, this identity names the logical workload, not an individual process: replicas of the same deployment present credentials for the same SPIFFE ID, while the per-team shape names one registered agent. Unlike a passport, nobody carries it around: it arrives over a local socket, lives for one hour, and renews automatically. The identity derives from what the agent verifiably is, never from what it knows. There is no password to steal because there is no password. For runtimes that cannot host a SPIRE agent, such as serverless microVMs, Vijil runs a delegate service that verifies cloud-provider-signed evidence of the agent's execution role before any identity is issued. Same principle, different attestor, carried in a five-minute JWT.

An attested identity does not make a compromised agent benign. An attacker who compromises a running workload can use its identity until the credential expires or the workload is terminated. The architecture removes credential portability and replay; it does not eliminate compromise. What remains is containment: limiting what the identity can do and detecting when it behaves incorrectly. Those are the next slivers in this series.
Proof then happens on every request through the proxy, not once at onboarding. When the agent calls a model through Vijil's proxy, it presents its SVID over mutual TLS. The Vijil proxy server resolves identity through a single fail-closed path: a verified certificate wins and there is no default identity. The proof immediately buys least privilege. The verified SPIFFE ID must match a configured route before the proxy server fetches the provider's API key from a secrets vault and forwards the call. The agent never holds the model provider's key.

The agent holds identity, not authority. Authority is released only when that identity is verified against policy.
The stack, named plainly: workload provenance (what execution environment produced this credential) feeds cryptographic identity (what name the trust domain assigns to it), which carries agent binding (which declared agent specification that identity corresponds to), which is the subject of authorization (what the identity may do), which gates capability release (which secrets and tools it may receive).
Caveat: identity is necessary for enforcement, not sufficient. What the runtime does about an unattested agent is an operator choice, and today the default is to warn rather than deny while attestation rolls out across deployments. If you want unattested agents refused, that switch exists; flip it deliberately.
Sidebar: where your IdP fits
Your identity provider still matters. It sits at a different layer.
Operators sign in to the Vijil Console through the IdP, the way they sign in to everything else. That login, plus a role check, is what authorizes the platform to enroll an agent and issue its identity. The operator's token is never handed to the agent: the human's identity authorizes the agent's birth certificate, and it never becomes the agent's passport.
The IdP appears once more, on the discovery side: Vijil reads the consent logs of identity providers like Okta to find the AI agents already operating in your estate. Your IdP tells us which agents exist. It never tells agents who they are.
How to use it
The developer-facing surface is deliberately small.
1. Label the workload. Identity issuance, rotation, and expiry follow from the platform's ClusterSPIFFEID templates; there is nothing to fetch and nowhere to paste it.
metadata:
labels:
vijil.ai/trust-runtime: "enabled"2. Install Dome with identity support, and start the runtime. pip install "vijil-dome[identity]". The runtime resolves the agent's SVID from the local socket when it starts; an install without the extra simply runs unattested.
from vijil_dome.trust.runtime import TrustRuntime
# agent_id is a local label for audit and constraints lookup;
# the attested identity comes from the SVID, not from this argument
runtime = TrustRuntime(agent_id="travel-agent", mode="enforce")
attestation = runtime.attest() # verifies every declared tool at boot3. Name your tools by identity, and wrap them. Each manifest entry carries the tool's own SPIFFE ID, so the runtime can verify that the tool answering is the tool declared. Wrapped tool functions pass through the runtime's checks on every call.
# one manifest entry per tool
{"name": "search_flights", "identity": "spiffe://vijil.ai/tools/flights/v1"}
# wrap the tool functions the agent will call
tools = runtime.wrap_tools([search_flights, create_booking])4. Route models by identity. Give the proxy server a route for your agent's SPIFFE ID or pattern, and remove the provider key from the agent's environment. That deletion is the point.
Why you should care
If you develop agents: you stop plumbing credentials. Add the label; the platform mints, renews, and expires the identity. Your agent code never touches a model provider's key (the proxy brokers it after the identity check), so a leaked container image or a prompt-injected agent has no provider secret to exfiltrate.
If you own the business: identity is the handle the entire agent lifecycle hangs on. You can finally answer the basic questions about your AI estate: which agents exist, who authorized them, what each one can access, which are still running, and which one produced this outcome. And security review stops stalling launches over secrets handling, because there are no shared secrets to review.
If you own the risk: your blast radius shrinks from a credential that outlives an employee to a certificate that expires in one hour. Every audit event is keyed to a cryptographic identity rather than a self-reported name. And the machinery is a graduated open standard: your platform teams already know how to operate it, and your auditors can read it in public.
Where to go from here
Start with the Vijil Dome documentation. Next time: once an agent can prove who it is, how exactly does Vijil give it only the tools it needs?



