AI Security

Securing Autonomous AI Pipelines

David Goldschlag · · 13 min read
Securing Autonomous AI Pipelines

Agentic AI pipelines — systems where an orchestrator spawns sub-agents, those sub-agents call external APIs and retrieve documents, and the results flow back into further reasoning steps — are being deployed into production environments that weren't designed to handle their security requirements. The identity question is the hardest one: what is calling what, with what authority, on behalf of whom, and how do you log it in a way that's useful?

This isn't a theoretical concern. When we look at how teams are deploying these systems today, the authentication patterns are what you'd expect from any early-stage infrastructure: API keys in environment variables, shared service accounts, no per-agent identity, and audit trails that record "the system called the external API" without capturing which agent invocation triggered it or what authorization decision allowed it.

Building a coherent identity model for autonomous AI pipelines requires solving several problems simultaneously: how to give each agent a distinct identity, how to scope that identity to the minimum necessary access, how to handle the parent-child delegation relationship when an orchestrator spawns sub-agents, and what the audit trail needs to look like to be operationally useful.

The Identity Surface in a Typical Agentic Pipeline

Consider a research pipeline: an orchestrator agent receives a user request, breaks it into sub-tasks, spawns a document retrieval agent and a web search agent, coordinates their outputs, and calls an external summarization API. The audit and access control surface includes:

  • The orchestrator's identity when it spawns sub-agents (orchestrator → sub-agent RPC)
  • The document retrieval agent's identity when it accesses the vector store or document database
  • The web search agent's identity when it calls the external search API
  • The orchestrator's identity when it calls the summarization API
  • Any upstream context — whose request triggered this pipeline run, with what authorization level

In a system without per-agent identity, all five access events look identical in the audit log: the same service account accessing the same resources. You can't tell which pipeline run triggered which access, or which agent within that run was responsible. When something goes wrong — an agent retrieves a document it shouldn't have access to, or a pipeline makes an unexpected external API call — you're left with aggregate logs rather than per-invocation attribution.

Per-Invocation Identity vs. Per-Agent-Type Identity

There are two ways to think about identity granularity in agentic systems:

Per-agent-type identity: All document retrieval agents share an identity, regardless of which pipeline run spawned them. Access policy is defined at the agent type level. The audit trail can distinguish "document retrieval agent accessed vector store" from "web search agent called search API," but can't distinguish between two document retrieval agents running concurrently in different pipeline invocations.

Per-invocation identity: Each agent instance — even agents of the same type — gets a distinct identity that encodes which pipeline run it belongs to. Access events are attributable to specific pipeline invocations. The cost is more complex identity management: you need to issue identities dynamically at agent spawn time rather than assigning them at deployment time.

For most production systems, per-agent-type identity is the right starting point. It's achievable with today's workload identity infrastructure and provides meaningful isolation: document retrieval agents have document access, web search agents have search API access, and neither has the other's permissions. Per-invocation identity is worth building toward for systems where pipeline-level attribution matters for compliance or incident response, but it requires infrastructure that most teams don't have yet.

Mapping the Agent Graph to an Identity Model

Each node in the agent graph needs a workload identity. For agents running as Kubernetes pods, this means distinct service accounts per agent type:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: orchestrator-agent
  namespace: ai-pipelines
  annotations:
    aembit.io/workload-class: orchestrator
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: retrieval-agent
  namespace: ai-pipelines
  annotations:
    aembit.io/workload-class: retrieval
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: search-agent
  namespace: ai-pipelines
  annotations:
    aembit.io/workload-class: search

Each service account maps to a SPIFFE ID: spiffe://cluster.internal/ns/ai-pipelines/sa/orchestrator-agent, etc. Aembit policies are defined against these SPIFFE IDs, specifying which server resources each agent type is allowed to access and under what conditions.

The orchestrator gets access to the sub-agent APIs and the summarization endpoint. The retrieval agent gets access to the vector store. The search agent gets access to the search API. No agent gets access to resources outside its defined scope — including, importantly, no agent gets access to the Aembit credential store directly or to credentials intended for other agent types.

The Delegation Problem

When an orchestrator spawns a sub-agent, there's an implicit delegation happening: the orchestrator is asking the sub-agent to perform work on behalf of a user request. If that user request has an associated authorization context — "this user is allowed to access documents in project X but not project Y" — you want that constraint to propagate through the sub-agent's actions.

This is the token delegation problem. OAuth 2.0 Token Exchange (RFC 8693) provides the technical mechanism: the orchestrator presents its own token plus the user's authorization token to a token exchange endpoint, which issues a new token for the sub-agent that carries the combined delegation context.

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJ...  (orchestrator's OIDC token)
&subject_token_type=urn:ietf:params:oauth:token-type:jwt
&actor_token=eyJ...   (user's authorization token)
&actor_token_type=urn:ietf:params:oauth:token-type:jwt
&audience=spiffe://cluster.internal/ns/ai-pipelines/sa/retrieval-agent
&scope=documents:read:project-x

The resulting token carries both the agent's identity (sub) and the delegation chain (act claim in RFC 8693). The vector store can enforce that this retrieval agent, acting under this delegation chain, may access project-X documents.

Most teams aren't implementing full delegation chains yet — it requires coordination between the agent runtime, the token exchange endpoint, and the resource servers. The pragmatic first step is to ensure that user-context constraints are enforced at the orchestrator level before work is delegated to sub-agents, accepting that sub-agents operate with the orchestrator's authority rather than a narrower delegated authority. This is less secure but much simpler to implement.

External API Authentication from Agents

When agents call external APIs — services outside your infrastructure — the authentication pattern is constrained by what those external services accept. Most accept API keys or OAuth client credentials; few accept SPIFFE-based identity tokens.

The solution is credential mediation at the boundary. The agent's outbound requests go through an egress proxy or credential injection layer that attaches the appropriate external credential based on the agent's identity and the destination. The agent itself never holds the external API key — it holds its own workload identity, and the mediation layer handles the translation to whatever the external service accepts.

In Aembit's model, this works through the outbound policy: when a workload with SPIFFE ID spiffe://cluster.internal/ns/ai-pipelines/sa/search-agent makes a request to api.searchprovider.com, Aembit injects the appropriate API key into the outbound request headers. The agent code makes a plain HTTP request; the identity layer handles credential attachment. The agent can't access the API key value directly — it can only trigger the authorized call through the mediation layer.

This model is especially valuable for external API keys because it keeps those keys out of every agent's environment. If an agent process is compromised, the attacker can trigger the authorized calls but can't extract the key for use outside the authorized call path.

Audit Trail Requirements

The audit trail for an agentic pipeline needs to answer: what ran, what did it access, and why was it authorized? The standard service-account-level log doesn't answer "why was it authorized" in a useful way.

Minimum useful audit fields for agentic pipeline events:

  • pipeline_run_id: Correlates all events in a single pipeline invocation
  • agent_type: Which type of agent made this call
  • agent_instance_id: Which specific instance, if using per-invocation identity
  • parent_agent: Which agent spawned this agent (delegation chain)
  • resource: What was accessed
  • operation: What was done (read, write, execute)
  • policy_id: Which access policy authorized this event
  • user_context_id: If the pipeline was user-triggered, which user authorization context applies

With pipeline_run_id as a correlation key, you can reconstruct the full access graph for a specific pipeline invocation. This matters for incident response — when investigating an unusual access event, you want to trace back to the original request that triggered the pipeline, not just see that a specific agent type made a specific API call.

Where Most Teams Are Getting This Wrong

The pattern we see most frequently is a single service account for the entire agentic system. All agents — orchestrator, retrieval, search, execution — authenticate as the same identity. The permissions on that service account are the union of everything any agent needs to do, which is typically broader than any single agent requires. There's no per-agent audit trail. A compromised agent has access to everything the system can access.

The fix isn't complicated — it's decomposing the single identity into per-agent-type identities and defining minimum-scope policies for each. The hard part is organizational: the team that built the pipeline needs to work with the security team to enumerate what each agent type actually needs to access, rather than assigning broad permissions that make the pipeline "just work."

We're not saying the current pattern is reckless given the speed at which these systems are being built. We're saying the technical debt is accumulating fast, and addressing it now — before these pipelines are handling sensitive customer data at scale — is significantly less painful than addressing it after an incident.