The Identity Problem for AI Agents
I've been exploring AWS Bedrock AgentCore and how it handles agent identity and security. The more I dug in, the more I realized the identity problem for AI agents is genuinely hard, and worth breaking down from scratch.
This is Part 1 of a three-part series. This post covers the problem space and the mental model. Part 2 covers how AgentCore Identity actually works. Part 3 covers real-world patterns, security properties, and lessons from the field.
What Goes Wrong Without Agent Identity
Let's start with a question that sounds simple but isn't: when an AI agent reads your Google Calendar to schedule a meeting, whose identity is it using?
Think about how things work without agents. You open Google Calendar in your browser. Google knows it's you because you logged in. You see your events. Your coworker sees theirs. Simple. The identity is clear, the access is clear, the boundary is clear.
Now throw an AI agent into the mix.
You tell your agent: "Schedule a meeting with Jamie next Tuesday." The agent needs to read your Google Calendar, check Jamie's availability, and create an event. But the agent is a piece of software running on a server somewhere. It's not you. It doesn't have your browser session. It doesn't have your Google password. It's a completely separate entity.
So how does it access your calendar?
The naive answer is: give the agent your Google credentials. But that's terrifying. You'd be handing over the keys to your entire Google account to a piece of software. It could read your emails, delete your files, impersonate you. And if the agent gets compromised, the attacker has everything.
Okay, so maybe we give the agent an API key? But API keys are static, long-lived secrets. They don't expire easily. They don't carry information about who the agent is acting for. And if you have 10,000 users, do you store 10,000 API keys? Where? How do you rotate them? How do you revoke one without affecting the others?
The root cause: we need a way for software (the agent) to act on behalf of a human (you), with limited permissions, for a limited time, and with a clear audit trail of who did what.
Three Identities, Not One
In the world of AI agents, there are actually three distinct identities in play. Getting confused about which is which is the source of most security mistakes in this space.
The End User (The Human). This is you. The person who says "schedule a meeting" or "summarize my emails." You authenticated with some identity provider, maybe Google, maybe Okta, maybe your company's SSO. You have a unique identifier and specific permissions.
The Agent Identity / Workload Identity (The Software). This is the agent itself. Not you, not any specific user, but the software application. Think of it like a robot employee: a first-class principal in your identity system with its own identity, its own permissions, and its own audit trail. Just like a human employee has a badge and a job description, the agent has an identity and a set of permissions.
In AWS's terminology, this is called a "workload identity." When you see "workload identity" in the AgentCore docs, think "agent identity." They're the same thing.
Why does the agent need its own identity? Because if Agent A and Agent B both access your calendar, we need to distinguish between them. Maybe Agent A is your trusted scheduling assistant, and Agent B is a rogue agent that somehow got access. Without separate agent identities, you can't tell them apart.
The Infrastructure Identity (The IAM Role). This is the underlying compute that runs the agent. In AWS, this is the IAM role attached to the Lambda function, ECS task, or EC2 instance. It's the identity of the machine, not the application logic.
This is NOT the same as the workload identity:
| Aspect | IAM Role | Workload Identity |
|---|---|---|
| Scope | AWS only | AWS + external (OAuth, API keys) |
| Identity | Temporary STS credentials | Persistent identity with ARN |
| User binding | No native user context | Binds agent + user identity pair |
| Credentials | STS tokens only | IAM + OAuth2 + API keys |
| Directory | No centralized registry | Single directory per account |
Why separate them? The same agent code might run in different environments with different IAM roles, and the same infrastructure might run different agents. The IAM role controls what AWS APIs the compute can call. The workload identity controls which agent this is and what credentials it can access.
So when your agent reads your Google Calendar, three identities are in play: you (the human who authorized it), the agent's workload identity (the software doing the work), and the IAM role (the infrastructure running the software).
The Agent Identity Directory
If you have 50 agents across different teams, how do you keep track of them all? How do you know which agents exist, who created them, and what they have access to?
Without a central registry, you'd have the same problem companies had before Active Directory: identities scattered everywhere, no single place to audit, no way to answer "how many agents do we have and what can they do?"
That's what the Agent Identity Directory solves. Think of it like Active Directory, but for AI agents instead of humans.
There's one directory per AWS account. It's auto-created when you create your first workload identity. Every workload identity, whether auto-created by Runtime, auto-created by Gateway, or manually created by you, shows up in the same directory.
workload-identity-directory/default
├── workload-identity/runtime-agent-1 (auto)
├── workload-identity/gateway-agent-1 (auto)
└── workload-identity/custom-agent-1 (manual)
Each workload identity has a unique ARN, metadata (name, OAuth return URLs, timestamps), and serves as a stable anchor whether you're using IAM roles, OAuth2 tokens, or API keys.
If you're using AgentCore Runtime, you don't have to manually create identities. Runtime auto-creates a workload identity when you deploy an agent. Gateway does the same. You only need to call CreateWorkloadIdentity manually for self-hosted agents (ECS, EKS, Lambda).
Three Access Tokens, Three Phases
Here's where it gets confusing fast. There are multiple tokens in this system, and they all serve different purposes. If you mix them up, nothing makes sense.
Token 1: The Human Access Token. A JWT issued by your identity provider (Okta, Cognito, Entra ID) when the end user logs into your web app. It proves "This is Alice. She authenticated with Okta at 10:03 AM." Your web app sends this to AgentCore Runtime in the Authorization header. This token has nothing to do with agents. It's a standard OAuth/OIDC token.
Token 2: The Workload Access Token (WAT). An AWS-signed opaque token that AgentCore generates internally. It binds two things together: the agent's workload identity and the end user's identity. It proves "This is the Calendar Agent, and it's currently acting on behalf of Alice." The agent uses this token when calling AgentCore's own services, specifically the Token Vault. It's only used within the AgentCore ecosystem, never sent to Google or any third-party service.
Token 3: The Resource Token. An OAuth 2.0 access token from a third-party service like Google, GitHub, or Salesforce. This is the token that actually lets you call the Google Drive API. It proves "Alice authorized this application to read her Google Drive files." Stored in AgentCore's Token Vault, retrieved by the agent when needed.
Here's how they flow together:
Phase 1: User Authentication
Alice logs into web app via IdP (Cognito/Okta)
-> IdP issues Human Access Token (JWT)
-> App sends prompt + JWT to AgentCore Runtime
Phase 2: Agent Interaction
Runtime validates JWT
-> AgentCore Identity issues WAT (agent + user bound)
-> Agent calls GetResourceOauth2Token with WAT
Phase 3: Agent Acts on Behalf of User
Token Vault returns Resource Token
-> Agent calls External API (Google/Slack) with resource token
-> Results returned to user
Three tokens. Three phases. Three different issuers. Three different destinations.
The workload identity is like your employee record in HR. The WAT is like your badge scan at the door. The human JWT is like the visitor badge your guest wears. The IAM role is like the building's security system that lets the badge reader work at all.
The Confused Deputy Problem
Here's a concrete attack scenario that shows why the WAT matters.
Imagine an agent that has broad permissions to access Google Drive on behalf of users. Without workload identity binding, an attacker invokes the agent. The agent has a Google Drive OAuth token stored for a victim user. Without any binding between "who is calling" and "whose credentials to use," the agent might use the victim's token to serve the attacker's request. The attacker sees the victim's files.
Classic confused deputy: the agent doesn't verify whose credentials it's using match who is asking.
With AgentCore Identity, this can't happen. Every credential in Token Vault is bound to agent identity + user identity. The WAT encodes both identities, so the agent can only retrieve tokens for the current user. User identity is derived from a cryptographically verified JWT. Cross-agent access is impossible because the WAT is scoped to one agent.
The key principle: every access request is validated independently. "Agent X accessed Resource Y on behalf of User Z" shows up as a full audit trail in CloudTrail.
What's Next
Now that you understand the problem space, the three identities, the three tokens, and why they matter, Part 2 dives into how AgentCore Identity actually works: the components, inbound authentication modes, outbound OAuth flows, and session binding.
Read Part 2: How AgentCore Identity Actually Works