IAM Policy Evaluation Edge Cases That AI Agents Frequently Misinterpret
AI agents operating through the AWS Agent Toolkit often encounter IAM access denials due to missing session tags, transitive tag propagation failures in role chaining, and unmet service-specific condition keys like aws:SourceArn that developers forget to include in cross-account or pass-role scenarios.
The AWS Agent Toolkit for AWS equips AI-assisted coding agents with plugins, skills, and an AWS MCP Server that enforce strict IAM controls by automatically injecting identity metadata into API requests. When policies rely on condition keys such as aws:PrincipalTag/AgentID or aws:CalledVia to restrict actions to agent-only contexts, subtle evaluation edge cases can trigger unexpected denials or permission leaks. Understanding these IAM policy evaluation edge cases is essential for writing secure, agent-aware policies that isolate agent permissions from broader developer IAM roles.
How the AWS Agent Toolkit Enforces IAM Controls
The toolkit routes all agent-initiated AWS calls through the MCP Server, which automatically attaches the agent’s identity as an IAM principal and injects IAM condition keys describing who the agent is and how it is acting. According to the repository’s documentation in README.md at lines 162-166, this design deliberately isolates agent permissions from the developer’s IAM role, enabling policies that allow actions only when they originate from an agent. The rules/aws-agent-rules.md file at lines 9-11 provides agents with explicit guidance to verify IAM-related details before acting, ensuring that condition keys like aws:PrincipalTag/AgentID and aws:CalledVia are present in every request.
Six Critical IAM Policy Evaluation Edge Cases
Missing or Mismatched Condition Tags
The agent must include the exact tag value the policy expects, such as AgentID=xyz. If the tag is omitted or a different value is supplied, the condition evaluates to false, resulting in "AccessDenied" even though the principal possesses the required IAM role. This occurs frequently when developers manually configure agents without using the toolkit’s automatic tag injection.
Assume-Role Chaining Without Transitive Tags
When an agent assumes a role that itself assumes another role, condition keys are not automatically propagated unless explicitly passed through TagSession or TransitiveTag options. Policies that allow sts:AssumeRole with a tag condition may succeed initially, but subsequent AWS service calls fail because the downstream role lacks the original agent tags. The toolkit’s helper libraries mitigate this by propagating original tags via TransitiveTagKeys.
Cross-Account Resource Policy Mismatches
Resource-based policies can grant permissions only when aws:PrincipalOrgID or aws:PrincipalArn matches a specific account. Agents running in a different account may be denied despite having sufficient role permissions, resulting in "AccessDenied" on S3 buckets or DynamoDB tables that are otherwise open to the role. The bucket policy must explicitly reference the agent’s principal ARN and expected tags.
IAM Pass-Role with Missing Service-Specific Conditions
Services like Lambda and ECS require additional condition keys such as aws:SourceArn when a role is passed. The agent may correctly pass the role but omit the required source ARN, causing the policy to reject the request with an "InvalidParameterException: Missing required parameter ‘SourceArn’" error. This edge case requires explicit condition statements in the IAM policy that the agent cannot satisfy without proper configuration.
Explicit Deny Evaluation with Unsupplied Condition Keys
An explicit Deny that uses a condition key not supplied by the agent, such as aws:RequestedRegion, will still block the action even if an Allow statement would otherwise succeed. This creates unexpected denials in regions where the agent is fully authorized, because the explicit deny logic evaluates independently of the presence of the condition key in the request context.
Policy Size and Evaluation Limits
Large, complex policies containing many statements or nested NotAction/NotResource elements can hit the 5,000-statement evaluation limit, causing requests to be rejected with a generic "Policy size exceeds the limit" error. This occurs during seemingly simple operations when policies accumulate deny statements or condition blocks for numerous edge cases.
Practical Code Examples for Handling Edge Cases
Assuming a Role with Session Tags
Use the TagSession and TransitiveTagKeys parameters to ensure tags survive role chaining:
import boto3
sts = boto3.client('sts')
agent_id = "agent-1234"
resp = sts.assume_role(
RoleArn='arn:aws:iam::111122223333:role/AgentRole',
RoleSessionName='agent-session',
Tags=[{'Key': 'AgentID', 'Value': agent_id}],
TransitiveTagKeys=['AgentID']
)
creds = resp['Credentials']
client = boto3.client('s3',
aws_access_key_id=creds['AccessKeyId'],
aws_secret_access_key=creds['SecretAccessKey'],
aws_session_token=creds['SessionToken'])
The corresponding policy grants s3:PutObject only when the tag matches:
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringEquals": {
"aws:PrincipalTag/AgentID": "agent-1234"
}
}
}
Enforcing Agent Identity with aws:CalledVia
The toolkit’s asm-exec wrapper automatically injects required condition keys:
asm-exec python create_table.py \
--agent-id ${AGENT_ID} \
--region us-east-1
This ensures the request carries aws:PrincipalTag/AgentID and aws:CalledVia = aws-agent-toolkit. The matching policy requires:
{
"Effect": "Allow",
"Action": "dynamodb:CreateTable",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:CalledVia": "aws-agent-toolkit"
}
}
}
Handling Cross-Account Resource Policies
When accessing a bucket in another account, the resource policy must reference the agent’s principal ARN:
{
"Sid": "AllowAgentRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:role/AgentRole"
},
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::shared-bucket/*",
"Condition": {
"StringEquals": {
"aws:PrincipalTag/AgentID": "agent-1234"
}
}
}
Key Source Files in the Agent Toolkit
plugins/aws-core/hooks/secret-safety.py– Enforces secret-handling guardrails that prevent agents from leaking credentials in IAM contexts.README.md(repo root) – Documents the overall architecture and the role of IAM condition keys in agent isolation at lines 162-166.rules/aws-agent-rules.md– Provides explicit guidance for agents to verify IAM-related details before acting at lines 9-11.skills/specialized-skills/database-skills/amazon-elasticache/scripts/test_connection.py– Implements concrete IAM authentication checks and prints helpful error messages when evaluations fail at lines 7-14.skills/specialized-skills/analytics-skills/migrate-to-msk/scripts/compatibility.py– Defines constants for IAM-related connection limits (e.g.,EXPRESS_MAX_IAM_CONNS_PER_BROKER) that illustrate how IAM authentication factors into service-specific quotas at lines 714-734.
Summary
- Condition key propagation failures during role chaining cause silent denials when
TransitiveTagKeysare omitted fromsts:AssumeRolecalls. - Cross-account resource policies must explicitly reference the agent’s principal ARN and expected tags, not just the assumed role.
- Service-specific conditions like
aws:SourceArnare mandatory for IAM pass-role operations in Lambda and ECS, and agents must include them in the request context. - Explicit deny statements evaluate independently of whether the agent supplies the condition key, potentially blocking authorized actions.
- Policy size limits of 5,000 statements can trigger unexpected errors when complex agent policies accumulate edge-case handling rules.
- Toolkit utilities like
asm-execand the MCP Server automatically inject standard condition keys, reducing the risk of missing tag mismatches.
Frequently Asked Questions
Why does my agent get "AccessDenied" despite having the correct IAM role?
This typically occurs when the IAM policy includes condition keys like aws:PrincipalTag/AgentID that the agent’s request does not include. Verify that the agent injected the correct tags during the sts:AssumeRole call or use the toolkit’s asm-exec wrapper to automatically handle tag propagation.
How do I fix permission failures when my agent assumes a role that assumes another role?
You must enable TagSession on every sts:AssumeRole call and specify TransitiveTagKeys to ensure condition keys propagate through the chain. Without this, the second assumed role loses the original agent identity tags, causing downstream service calls to fail.
What causes "InvalidParameterException: Missing required parameter ‘SourceArn’" when passing IAM roles?
Services like Lambda and ECS require the aws:SourceArn condition key in the IAM policy when passing roles. The agent must include this in the request context, or you must adjust the policy to allow the pass-role action without that specific condition if the service supports it.
Do explicit deny statements in IAM policies affect agents differently than allow statements?
Yes. An explicit Deny with a condition key evaluates to true if the condition key is missing from the request, whereas an Allow with a condition key evaluates to false. This means a missing aws:RequestedRegion condition in the agent’s request will trigger an explicit deny but would not trigger an explicit allow, creating asymmetric blocking behavior.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →