Ask an enterprise team how they do identity and access management for AI agents and you get one of two answers. Either they have not started, or they have an agent role in AWS IAM with a long-lived access key and a policy that is the union of every permission any task might conceivably need. The second answer is worse, because it looks finished.
The practical answer is narrower than most architecture decks suggest. Give every agent its own identity, never a shared service account. Issue short-lived, session-scoped credentials instead of static keys. Authorize each action at the tool boundary, server-side, using both the agent identity and the identity of the human or system that initiated the work. Then emit traces that let you replay who asked, which agent acted, under which credential, against which resource, and what came back. Those four moves are the whole framework. Everything else is implementation detail.
Three failure signatures tell you the framework is missing. Permission unions, where one role accumulates every entitlement any workflow touched. Confused-deputy tool calls, where an agent acting for a low-privilege user executes something only the agent role was ever allowed to do. And audit logs that name a role instead of an actor, so an incident review can tell you AgentExecutionRole deleted the record but not which task, which prompt, or which person started the chain.
The Service Account That Became an Autonomous Actor
The human-user access model assumes access requests are predictable and reviewable on a quarterly cadence. A person gets a role, the role maps to a job function, and an access review confirms the mapping still holds. Agents break every assumption in that sentence.
Agents request tool access dynamically in the middle of a task. They chain credentials across services, where a retrieval step produces the input to a write step. And they generate action sequences that no access review anticipated, because the sequence is composed at runtime by a model, not at design time by an engineer.
That is why "we gave the agent a service account" is not zero trust. It is the opposite: one implicit trust boundary wrapped around a non-deterministic actor. Agent-to-tool integration is consolidating on the Model Context Protocol, which specifies how clients, servers, tools, and resources interact and includes an authorization approach for HTTP-based transports [1]. The important consequence for security teams is that tool access becomes a reviewable interface contract instead of prompt text. You can audit an interface. You cannot audit an instruction that says "only use this tool for read operations."
Four Identity Layers Every Agent Call Crosses
Most agent incidents trace back to collapsing four distinct identities into one. Separate them explicitly and the authorization logic gets simpler, not harder.
The initiating principal is the human or upstream system that started the work. The agent identity is the software actor executing the plan. The tool or MCP server identity is the component that validates and performs the call. The downstream resource principal is whatever credential actually touches the database, queue, or API. Each proves something different, and each is enforced in a different place.
On-behalf-of authorization is where this matters most in practice. If a support agent handles a request from a tier-one representative who cannot issue refunds, the agent must not complete a refund simply because the agent role has the entitlement. MCP authorization guidance for HTTP transports allows both agent identity and user identity to be enforced server-side at the tool boundary [1], which is the only place that check holds when the prompt is attacker-influenced.
| Identity layer | What it proves | Where enforced | Failure if missing |
|---|---|---|---|
| Initiating principal | A named human or system started this work | Application session, propagated as caller context | Audit records name a role, not an actor |
| Agent identity | Which agent build and configuration acted | Per-agent IAM role, one per agent, no sharing | Cannot isolate or revoke a single misbehaving agent |
| Delegation context | The agent is acting for a specific user, with that user's limits | Tool boundary, evaluated with user claims | Confused deputy: low-privilege user gets agent-level power |
| Tool / MCP server identity | The call came through a governed interface with a schema | MCP server authorization check, server-side [1] | Prompt text becomes the access control mechanism |
| Resource principal | Which credential touched which resource | Scoped session credential plus resource policy conditions | Blast radius equals the union of all agent permissions |
Treat each tool as a governed interface with a schema, scoped credentials, rate limits, idempotency behavior, and an explicit read-only versus write-capable classification [1]. Once tools look like interfaces, access reviews stop being prompt reviews and start being contract reviews, which your existing security process already knows how to run.
Short-Lived Credentials Without an Operational Bottleneck
The issuance pattern that works: the agent harness assumes a per-agent role for each session and attaches a session policy that narrows the role's permissions down to the current task scope. The role defines the maximum. The session policy defines what this task actually needs. Effective permissions are the intersection, which means a broad role cannot accidentally widen a narrow task. Verify the intersection semantics for your account against current AWS IAM documentation before you depend on them.
Carry caller context into the credential itself using session tags: initiating principal, task ID, tenant, and data classification. Then write resource policy conditions that reference those tags, so downstream authorization can evaluate context the agent cannot forge at the prompt layer.
Here is the pattern to retire:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AgentDoesEverything",
"Effect": "Allow",
"Action": ["s3:*", "dynamodb:*", "lambda:InvokeFunction"],
"Resource": "*"
}]
}Attached to a long-lived access key shared by three agents, that policy gives you no isolation, no revocation path, and no way to answer which agent did what.
And the pattern that replaces it, applied as a session policy at assume-role time:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ThisTaskOnly",
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:Query"],
"Resource": "arn:aws:dynamodb:us-east-1:111122223333:table/Tickets",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${aws:PrincipalTag/tenant}"]
},
"StringEquals": {
"aws:PrincipalTag/data_class": "internal"
}
}
}]
}The tenant condition does the isolating work. dynamodb:LeadingKeys requires the partition key of every item the session touches to equal the caller's own tenant tag, so a session issued for one tenant cannot read another tenant's rows even though both share the table and the role. Comparing a principal tag with itself would only prove the tag resolves.
Avoiding a bottleneck is mostly a design choice. Pre-approve permission templates per tool class (read-only retrieval, write-capable record update, irreversible financial action), automate issuance inside the agent harness, and reserve human approval for escalation requests that exceed the template. Approval per task does not scale. Approval per template does.
The common objection is that short-lived credentials break long-running workflows. They do not, if the workflow checkpoints. Persist task state, let the credential expire, and re-authorize on resume with the same caller context. A workflow that cannot survive re-authorization has a durability problem that the credential lifetime merely exposed.
Per-Action Authorization: Read-Only, Write-Capable, Irreversible
Tool-level allow lists are too coarse, because the same tool serves both harmless and destructive calls. A records.update tool that corrects a typo and a records.update tool that changes a payment destination are the same entry in your allow list and wildly different in consequence.
Classify actions in three tiers and attach a control to each:
- Read-only: retrieval, search, lookup. Control is scope, not approval. Restrict by tenant, row, and column, and log the query.
- Write-capable but compensable: status changes, ticket updates, draft creation. Require idempotency keys and a defined compensating action, then let the agent proceed.
- Irreversible: payments, deletions, external commitments to customers. Require human confirmation or a second independent check before execution [1].
Idempotency keys are the default for everything not gated by a human, because agent retry loops are normal, not exceptional. An agent that retries a compensable write three times should produce one effect, not three.
Content and topic controls belong outside the prompt. Amazon Bedrock Guardrails apply content filters, denied topics, and sensitive-information handling independently of the model and the prompt [3], which means a prompt refactor cannot silently remove them. That property matters more than the filter quality itself: controls that live in the prompt have no change control.
The tier decision teams most often skip is the middle one. They gate payments and allow everything else, which leaves a long tail of compensable writes with no compensating action actually implemented.
Audit Trails an Auditor Will Actually Accept
An agent audit record has to answer five questions: who initiated the work, which agent executed it, under which credential, against which resource, and with what result. If any of the five is missing, the record supports a narrative but not a finding.
OpenTelemetry generative-AI semantic conventions let model calls, tool invocations, and token usage be captured as standard telemetry with defined span and attribute names rather than bespoke logs [2]. The operational payoff is that agent traces flow into the same backends as your service traces, so an on-call engineer diagnoses an agent incident with the tooling they already use. The governance payoff is that your evidence has a schema, which means you can query it, retain it, and test it.
Correlate those spans with resource-level API events. Propagate the trace ID and task ID as session tags and request context so a CloudTrail entry showing a table write can be walked back to the originating agent step and the human principal who started the task. Without that correlation, cloud audit logs tell you a role acted and stop there.
Prompt and trace stores hold sensitive inputs, so treat retention and access as automatable controls: fixed retention windows, restricted read access, redaction of sensitive fields at ingest, and evidence collection wired into CI and telemetry rather than collected by hand at audit time.
Mapping Agent Access Controls to NIST, ISO 42001, and the EU AI Act
Build one internal control set and map it three ways. Maintaining parallel governance programs for each instrument is how governance becomes a paperwork function.
The instruments do different jobs. The NIST AI Risk Management Framework supplies a function-based operating model of Govern, Map, Measure, and Manage [4]. NIST AI 600-1, the Generative AI Profile, enumerates generative-specific risks including data leakage and provenance along with suggested actions [5]. ISO/IEC 42001 specifies requirements for an AI management system, which is the artifact an external auditor can certify against because it is written as a management-system standard with documented roles, objectives, and controls [6]. Regulation (EU) 2024/1689 is binding law with obligations tied to risk classification and to general-purpose AI models [7].
| Agent access control | What it enforces | Evidence artifact | Maps to |
|---|---|---|---|
| One identity per agent | No shared service accounts; per-agent revocation | IAM role inventory with agent-to-role mapping | AI RMF Govern [4]; ISO/IEC 42001 roles and responsibilities [6] |
| Session-scoped credentials | Least privilege per task, not per role | Assume-role logs with session policy and session tags | AI RMF Manage [4]; ISO/IEC 42001 operational control [6] |
| Tool-boundary authorization | Agent and user identity checked server-side [1] | MCP server authorization config and decision logs | AI RMF Measure [4]; EU AI Act risk-management obligations [7] |
| Irreversible-action gate | Human confirmation or second check before execution | Approval records linked to trace and task ID | AI 600-1 harmful-action risks [5]; EU AI Act human oversight [7] |
| Prompt-independent guardrails | Filters and denied topics survive prompt changes [3] | Guardrail version history and block-event logs | AI 600-1 data leakage and harmful output [5] |
| Traceable audit records | Five-question answerability per action [2] | OTel gen-AI spans plus correlated cloud audit events | AI RMF Measure [4]; ISO/IEC 42001 internal audit [6] |
The use-case inventory drives the tier. Record owner, data touched, decisions influenced, and human-in-the-loop design for every agent, and let that record determine whether the agent gets read-only scope, compensable write scope, or a gated irreversible path. Our work on AI governance frameworks for enterprise AI programs follows this sequence: inventory first, control tier second, evidence automation third.
A 30-Day Rollout Sequence for Agent Identity
Four weeks is enough to retire shared credentials if you sequence it and resist the urge to redesign everything at once.
- 1Week 1: inventory. List every agent in the estate and the credential it uses today. Flag every static key, every shared role, and every policy containing a wildcard action or resource. Output is a table, not a plan.
- 2Week 2: split identities. Create one role per agent. Copy existing permissions verbatim at first so nothing breaks, then narrow from evidence. Use IAM action last accessed data to propose removals, and read it as a shortlist, not a verdict: it does not report data plane calls such as object reads, and it does not track
iam:PassRole, so an action can look unused while a workload depends on it. Confirm each candidate against CloudTrail for the same window, deny it first and watch for failures, and only then remove it. Delete the shared role when the last consumer moves off it. - 3Week 3: governed tool interfaces. Move direct SDK calls behind MCP servers with schemas, scoped credentials, rate limits, idempotency, and read-only versus write-capable classification [1]. Enforce agent and user identity checks server-side at that boundary.
- 4Week 4: session-scoped issuance. Switch the harness to per-session role assumption with session policies and session tags. Turn off static keys. Keep the deny logs visible for the first week after cutover.
Readiness checklist before any agent gets write access to a production system:
- Named identity: the agent has its own role, and no other workload assumes it. Pass criteria: role trust policy names exactly one agent principal.
- Credential lifetime: no static keys in the execution path. Pass criteria: every tool call presents a session credential.
- Caller context: initiating principal and task ID present on every call. Pass criteria: a random production trace resolves to a named human or system.
- Action classification: every tool is labeled read-only, compensable, or irreversible. Pass criteria: no unlabeled tools in the registry.
- Deny visibility: authorization denials are logged and alertable. Pass criteria: a synthetic denied call appears in the dashboard within the alerting window.
- Regression gate: the agent passes its scenario suite with zero critical rule violations across repeated trials before any scope expansion ships [8]. Managed evaluation jobs can carry part of this load [9].
Borrow the promotion gate from evaluation practice rather than inventing a security-only gate. A permission expansion is a release, and it should pass the same regression run that a prompt or model change does. Teams building this end to end usually pair it with an agentic AI delivery and operating model so identity, evaluation, and observability ship together instead of in sequence.
Measure one thing in week one: the percentage of agent actions traceable to a named human or system initiator. If that number is below 100, the rest of the program is guesswork.
Frequently Asked Questions
Can agents share a service account?
No. Shared identities make per-agent revocation impossible and make audit records ambiguous, because the log names the role rather than the actor. One role per agent, with a trust policy that names a single principal.
What is the right credential lifetime for an agent?
Short enough that a leaked credential expires before it is useful, and long enough to cover one task step. Pick the shortest lifetime your harness can renew reliably, then make long-running workflows checkpoint and re-authorize rather than extending the credential.
Do we need a separate identity provider for agents?
Usually not a separate provider, but you do need separate principal types and separate lifecycle. Agents get their own identities, their own owners, and their own deprovisioning path when a build is retired.
How do we authorize an agent acting on behalf of a user?
Pass the user's identity and claims to the tool boundary and evaluate both identities there, server-side [1]. The effective permission is the intersection of what the agent may do and what the user may do, never the union.
What belongs in an agent audit record?
Initiating principal, agent identity and build version, credential and session tags, tool and resource targeted, authorization decision including denials, and the result. Emit it as OpenTelemetry gen-AI spans so it lands in the same backend as your service traces [2].
What to Do in Your Next Working Session
Pull the IAM policies attached to every agent role and list every action no agent has actually invoked in the last 30 days. That list is your review queue, not a deletion batch, and it is usually longer than the team expects. Confirm each entry against CloudTrail before you cut it, because action last accessed data omits data plane calls and iam:PassRole.
Start tracking one metric this week: the share of agent tool calls authorized with a session-scoped credential rather than a static role. That ratio is the single clearest measure of whether the over-permissioned service account is still running your agents, or whether you have replaced it with identities, scopes, and records an auditor can read.
References
[1]Model Context Protocol, "Specification (2025-06-18)," 2025. https://modelcontextprotocol.io/specification/2025-06-18
[2]OpenTelemetry, "Semantic Conventions for Generative AI," 2025. https://opentelemetry.io/docs/specs/semconv/gen-ai/
[3]Amazon Web Services, "Amazon Bedrock Guardrails," 2025. https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html
[4]NIST, "AI Risk Management Framework," 2025. https://www.nist.gov/itl/ai-risk-management-framework
[5]NIST, "AI 600-1: Generative AI Profile," 2024. https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.600-1.pdf
[6]ISO, "ISO/IEC 42001: Artificial intelligence management system," 2023. https://www.iso.org/standard/81230.html
[7]EUR-Lex, "Regulation (EU) 2024/1689 (EU AI Act)," 2024. https://eur-lex.europa.eu/eli/reg/2024/1689/oj
[8]Yao et al., "tau-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains," 2024. https://arxiv.org/abs/2406.12045
[9]Amazon Web Services, "Amazon Bedrock User Guide: Evaluation," 2025. https://docs.aws.amazon.com/bedrock/latest/userguide/evaluation.html
[10]Amazon Web Services, "AWS Well-Architected Framework," 2025. https://docs.aws.amazon.com/wellarchitected/latest/framework/welcome.html