IAM Policy Enforcement

Simfra evaluates IAM policies on every API call using the same logic as real AWS. This is not a stub or passthrough - it implements the full IAM policy evaluation logic.

Evaluation Chain

Every request is evaluated in this order:

  1. Explicit deny - If any applicable policy explicitly denies the action, the request is denied immediately.
  2. Service Control Policies (SCPs) - If the account is part of an Organization, SCPs set the maximum permissions. If no SCP allows the action, it is denied.
  3. Resource-based policies - Policies attached to the target resource (S3 bucket policies, SQS queue policies, Lambda function policies, etc.). A resource policy can grant cross-account access directly.
  4. Permission boundaries - If set on the IAM entity, the action must be allowed by both the identity policy and the boundary.
  5. Identity-based policies - Policies attached to the IAM user, group, or role making the request.
  6. Session policies - For assumed role or federated sessions, session policies further restrict permissions.

The default is implicit deny. Access is only granted when an Allow is found and no Deny overrides it.

Root Credentials

Requests signed with root account credentials (the root access key) bypass IAM evaluation entirely, matching AWS behavior.

Example: Testing Least-Privilege Access

Create an IAM user with a restricted policy and verify it works as expected:

export AWS_ENDPOINT_URL=http://localhost:4599

# Create a user
aws iam create-user --user-name developer

# Create an access key
aws iam create-access-key --user-name developer
# Note the AccessKeyId and SecretAccessKey

# Attach a policy that only allows S3 read
aws iam put-user-policy --user-name developer --policy-name s3-read \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": "*"
    }]
  }'

# Switch to the developer's credentials
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...

# This works:
aws s3 ls

# This is denied:
aws s3 mb s3://new-bucket
# Error: AccessDenied

Resource Policies

Services that support resource-based policies enforce them on every request:

  • S3 - Bucket policies
  • SQS - Queue policies
  • SNS - Topic policies
  • Lambda - Function policies
  • KMS - Key policies
  • Secrets Manager - Resource policies
  • CloudWatch Logs - Resource policies
  • EventBridge - Event bus policies
  • ECR - Repository policies
  • Glacier - Vault lock and access policies

Resource policies are also evaluated during cross-service delivery (e.g., SNS delivering to an SQS queue checks the queue's resource policy).

iam:PassRole

Every API that accepts a role ARN (Lambda CreateFunction, ECS RegisterTaskDefinition, EventBridge PutTargets, etc.) validates:

  1. The role exists in IAM.
  2. The caller has iam:PassRole permission for that role.

This matches AWS behavior and prevents privilege escalation.

Service-Linked Roles

Services that need service-linked roles (ECS, ELBv2, RDS, ElastiCache, EKS, etc.) auto-create them on first use, but only if the caller has iam:CreateServiceLinkedRole permission.

Organizations and SCPs

When using the Organizations service:

  1. Create an organization and organizational units.
  2. Attach SCPs to OUs or accounts.
  3. SCPs are enforced on every API call from member accounts.

SCPs set the maximum permissions for an account. Even if an IAM policy allows an action, if no SCP allows it, the request is denied.

Cross-Service Delivery Authorization

When services interact at runtime (SNS delivering to SQS, EventBridge triggering Lambda), the delivery is authorized using the appropriate model:

  • Resource-policy model: The target resource's policy is checked to verify the source service is permitted (e.g., SQS queue policy allowing sns.amazonaws.com).
  • Execution-role model: The source service assumes an execution role, and the role's identity policies authorize the target action (e.g., EventBridge Scheduler assuming a role to invoke Lambda).
  • Poller model: The consumer's execution role authorizes reads from the source (e.g., Lambda ESM reading from SQS).

IAM identity-based policies do not apply to service-to-service calls - only the target's resource policy or the execution role's policies are evaluated, matching how AWS works internally.