Agent identity vs service account: the worker is not the workload

Part of: Agent Identity

Agent identity vs service account is a layering split: the SA authenticates the worker pod, the agent needs its own principal that can be revoked per session.

Agent identity vs service account is a layering split: the SA authenticates the worker pod, and the agent needs its own principal that can be revoked per session. IRSA, GKE Workload Identity, and a projected SA token are how a pod proves it is a pod. They are not the agent’s name.

I see the mix-up whenever someone says “we already have IRSA.” I use those mechanisms. I built a federation lab on that shape. They remain the bootstrap, not the badge.

Is a Kubernetes service account enough for agent identity?

It is enough for the pod. It is not enough for a multiplexed actor, and it is a coarse fit even for one agent per pod because it does not name the session or the human the agent is acting for.

Kubernetes has published an unauthenticated OIDC discovery document and JWKS on the API server since 1.24. A projected service account token is a real identity: signed, short-lived, audience-bound if you set the audience. In the federation lab the projected token expires after 600 seconds and is minted for audience: wif-exchange. The default token, audience https://kubernetes.default.svc, authenticates the pod to the Kubernetes API and nothing else. The exchange refuses it with 401. That is a good SA. It is still a pod identity.

On a Deployment with one agent, revoking the pod revokes the agent. You also revoke every replica. You still cannot tell session 7 from session 400 in the log. Coarse is not false. Coarse is what you get when the only principal Kubernetes will give you is the pod.

Proof of agent identity asks four questions the SA cannot answer: which named agent, which session, on whose behalf, and what can I revoke without disabling a human or deleting a shared worker identity.

The series index is agent identity on Kubernetes .

Why does Agent Substrate make the mix-up false instead of merely coarse?

Many actors, one worker, one SA. The SA says “a bay in this pool spoke.” That is proof of a pool, which is useless in an incident.

Agent Substrate restores an actor onto a free worker, one actor per sandbox, then checkpoints and frees the slot. Nine agents on two worker pods in the first lab. Eighteen on the same two later. Live assignment lives in ateapi, not in a pod annotation. Kubernetes sees WorkerPool and ActorTemplate. kagent Agent Substrate . Agent Substrate dataplane .

If the audit log says system:serviceaccount:kagent:kagent-default for every tool call from every agent, you cannot isolate a refund-agent incident from a payroll-agent incident without reading the prompt. The reviewer will blame the pool. The pool will still be running tomorrow.

The July 2026 intrusion started cluster reconnaissance by reading the projected service account token from a compromised worker pod, then querying the cluster API and the public EKS endpoint. Twelve and a half hours later it held cluster-admin on multiple clusters. That token was the pod’s. automountServiceAccountToken: false unless the workload genuinely calls the API server. NetworkPolicy that denies egress to the API server from a data-processing namespace removes the reconnaissance step. Neither of those makes the SA into an agent identity. They stop the SA from being a cluster-admin bootstrap. Rogue agent Kubernetes controls .

People love to grant the worker get secrets because the agent might need a key. That is how every actor on the pool reads every key. I ran the other half of that story: RBAC, restricted Pod Security, automountServiceAccountToken: false, read-only root filesystem, and a mounted LLM key was still readable from /proc/1/environ. Kubernetes admission and RBAC govern access to Secret objects. They are not controls on a credential a pod has already been given. Agent LLM key Kubernetes controls .

When should an agent still use a service account?

To bootstrap.

The worker or pod presents an SA token to an exchange, and the exchange mints the agent credential. The SA is the platform’s statement about the process. The minted token is the agent’s.

worker SA  ->  exchange  ->  agent-scoped, audience-bound, short-lived token

The SA never goes to the tool. The agent token never lives in the snapshot. Suspend and resume agents .

RBAC on the SA stays tight: it can talk to the exchange and nothing else. In the federation lab, the exchange’s own ClusterRole grants exactly the two nonResourceURLs it needs to read the cluster JWKS. The agent SA maps to an explicit resource list in roles.yaml. No wildcard. A request for /billing is 403 before any token is minted. A valid /data token replayed at /billing is 403 from the destination, because audience is checked on both sides.

kagent v0.10.0 can send RFC 8707 resource indicators on that exchange. Both environment variables default to empty. Empty means unscoped. Set them. kagent audience-bound tokens .

SPIFFE is the attested version of the same split. The process asks the Workload API who it is. There is no key file. The gateway authorizes on source.spiffeId. SPIFFE for AI agents . Secretless AI agents is the inbound identity, outbound provider-key split.

When is the service account the right principal?

Node plumbing. Snapshot movers. atelet talking to a bucket via a node identity. Those are platform processes. They should not share an identity with the refund agent.

IAM for the bucket: atelet needs put/get on that prefix, not on the whole account. Actors should not have the bucket credential at all. A checkpoint is a copy. Copies leak. Agent checkpoint to object storage .

The worker SA is already a pod. Kubernetes will keep authenticating it whether you care or not. Put the real identity on the agent. If you can only afford one real identity this quarter, put it on the agent, not on the worker.

How do you tell you have confused the two?

The audit log names a namespace ServiceAccount for every agent in the pool, or revoking one agent requires deleting a pod identity shared by others. Proof of agent identity would survive both checks.

The human’s OAuth is a third principal. Do not stuff it in the SA, and do not confuse it with the agent. Why OAuth is not enough for agents . MCP’s Enterprise-Managed Authorization authenticates the employee. That is the right control for the human-to-agent grant. It is not a WorkerPool identity. MCP agent identity gap .

If you cannot name the agent in the allow rule, you do not have agent identity. You have a mesh. Kubernetes Network Policy for agents will never name it for you. Zero trust architecture for AI agents needs the principal on layer 3.

Checklist

  • Worker SA can reach the exchange, and nothing else. No get secrets.
  • automountServiceAccountToken: false on actors that do not call the API server.
  • Projected token audience is the exchange, not https://kubernetes.default.svc.
  • Minted token is audience-bound to one backend. Replay against a second backend is 403.
  • Audit line names the agent and the session, not only the namespace SA.
  • Revoke agent A without deleting the WorkerPool SA and without disabling the human.
  • Snapshot contains no SA token, no cloud key, no user refresh token.
  • atelet and other node plumbing use a platform identity, not the refund agent’s.

Field guide: Agent Substrate .

Frequently asked questions

Is a Kubernetes service account enough for agent identity?

It is enough for the pod. It is not enough for a multiplexed actor, and it is a coarse fit even for one agent per pod because it does not name the session or the human the agent is acting for.

When should an agent still use a service account?

To bootstrap. The worker or pod presents an SA token to an exchange, and the exchange mints the agent credential. The SA is the platform’s statement about the process. The minted token is the agent’s.

How do I tell I have confused the two?

The audit log names a namespace ServiceAccount for every agent in the pool, or revoking one agent requires deleting a pod identity shared by others. Proof of agent identity would survive both checks.

Should platform processes share an identity with the refund agent?

No. Snapshot movers and node plumbing should use a node or platform identity. They should not share an identity with the actor. atelet talking to a bucket is not the refund agent.

Where does the human's OAuth token sit in this split?

It is a third principal. Do not stuff it in the SA, and do not confuse it with the agent. Use it for the human-to-agent grant, then mint an agent credential for the turn.

Disagree or have a war story? Reply on X