Many 2026 AI agents are implemented as cloud function chains: the agent receives a request, invokes a Lambda to query a database, another to send an email, another to generate a PDF. Practical architecture, scalable, fragile on one specific point: each function runs with an IAM role whose permissions are inherited by the agent. An over-broad IAM scope turns a compromised agent into broad cloud access.
The minimum IAM posture is one of the most effective — and most neglected — levers in AI agent security.
The common pattern and its flaw
Typical architecture:
`` user → agent (orchestrator, EC2 or Lambda) → Lambda A (reads customer DB) → Lambda B (sends email via SES) → Lambda C (generates PDF in S3) ``
Common pattern: each Lambda has an IAM role, those roles often hold too-broad permissions ("AmazonSESFullAccess", "AmazonS3FullAccess") because that passes tests fastest and you need to ship.
Consequence: if the agent is compromised and invokes Lambda B with hijacked parameters, it could send email to anyone (not just the requested customer). C hijacked, the agent writes anywhere in S3.
5 IAM principles for an AI agent
1. One IAM role per function, never shared
Each cloud function has its own role. No "generic agent" role shared across functions. If function A is compromised, its role gets revoked without breaking B and C.
2. Resource-level permissions, not service-level
Bad: ``json {"Effect": "Allow", "Action": "s3:", "Resource": ""} ``
Good: ``json { "Effect": "Allow", "Action": ["s3:PutObject"], "Resource": "arn:aws:s3:::weesec-pdfs/clients/${aws:PrincipalTag/UserId}/*" } ``
Limited to exact action (s3:PutObject, not s3:*) and to a bucket sub-perimeter. If compromised, the attacker writes only into the current user's folder.
3. IAM conditions for context
IAM supports conditions: only from VPC X, only during business hours, only on objects matching a pattern.
``json { "Condition": { "StringEquals": {"aws:SourceVpc": "vpc-internal-prod"} } } ``
Very useful to limit a permission to its intended context. An external attacker can't activate the permission.
4. Tagging and ABAC (attribute-based access control)
For multi-tenant agents, ABAC scopes permissions per tenant via tags. The role holds a generic permission, principal and resource tags do the matching.
``json { "Effect": "Allow", "Action": "dynamodb:Query", "Resource": "*", "Condition": { "StringEquals": { "dynamodb:LeadingKeys": "${aws:PrincipalTag/TenantId}" } } } ``
The agent queries the DB but only records matching its tenant. Cross-tenant isolation guaranteed at IAM level, not just code level.
5. No long-lived credentials in agent runtime
The agent never stores long-lived AWS_ACCESS_KEY_ID. It uses:
- Instance role on EC2.
- Task role on ECS / Fargate.
- Function role on Lambda.
- OIDC federation elsewhere (GitHub Actions, on-prem, other cloud).
Ephemeral token, fetched on demand, no persistent credentials.
Agent-specific mistakes
"Read-all so the agent can 'understand context'"
Classic temptation: give the agent broad read access "so it can find what it needs". Antipattern. An agent needing to read 30 tables is probably mis-scoped on UX — it should have more specific tools.
Agent writing to the same DB as human services
If the agent writes to the prod DB with a broad role, a bug or manipulation can corrupt critical data. Defensive pattern: write to an intermediate table or outbox the agent can freely fill, with a separate process validating before integration.
Agent that assumes a role above its perimeter
With AssumeRole, an agent can temporarily take a stronger role. Strictly control this:
- Explicit allowlist of assumable roles.
- AssumeRole audit trail.
- No AssumeRole letting elevation to admin.
Periodic IAM review
Every 3 months, per role used by an agent:
- List actions actually used over the period (CloudTrail / GCP Audit Logs / Azure Monitor).
- Compare with actions allowed by policy.
- Remove allowed but unused actions.
Partially automatable. AWS offers IAM Access Analyzer to suggest policies based on real usage. Good baseline, complete with human review.
Special case: MCP servers running as cloud functions
If you expose an MCP tool running via Lambda, that Lambda's permissions indirectly become the calling agent's permissions. Treat with same care.
Good practice: dedicated IAM role per MCP tool, never reused. If "send_email" is compromised, "delete_file" keeps its own role.
Validation checklist
Before agent go-live invoking cloud:
- [ ] Each cloud function has its own IAM role.
- [ ] No role has
:(noAction:, no unscopedResource:). - [ ] Resources named precisely or matched via restrictive patterns.
- [ ] No long-lived credentials in agent runtime.
- [ ] Audit log enabled on all sensitive functions.
- [ ] Quarterly IAM review scheduled.
5 of 6 yes = top 10% of deployments. 3 yes = good start. 0-2 yes = don't ship on a sensitive scope.