Docs / IAM Enforcement

IAM Policy Enforcement

Evaluate IAM policies on every API request before service dispatch. Test your permission boundaries, resource policies, and least-privilege setups locally.

Enabling IAM Enforcement

Strict mode: denied requests return 403 AccessDenied

Terminal
$ IAM_ENFORCEMENT=1 localemu start
IAM policy enforcement: enabled
Ready.

Soft mode: denied requests are logged but still allowed

Terminal
$ IAM_ENFORCEMENT=soft localemu start
IAM policy enforcement: soft mode (log only)
Ready.

# Denied requests are logged but still allowed:
WARN IAM: would deny s3:GetObject for arn:aws:iam::000000000000:user/dev on arn:aws:s3:::my-bucket/*

Soft mode is useful for auditing existing workflows before switching to strict enforcement.

How It Works

Every API request is intercepted before it reaches the service handler. The enforcement engine extracts the caller identity, the action, and the target resource, then evaluates all applicable policies using the AWS policy evaluation algorithm:

1. Explicit deny in any policy results in immediate denial
2. Resource-based policy is evaluated (S3 bucket policy, SQS queue policy, etc.)
3. Identity-based policy is evaluated (user/role/group policies)
4. Permission boundary is checked (if attached to the principal)
5. If no explicit allow is found, the request is denied by default

Supported Policy Features

Feature Details
Action matchingExact match, wildcards (s3:*, s3:Get*)
Resource matchingFull ARN matching with wildcards
NotAction / NotResourceInverse matching for actions and resources
Condition operators26 operators: StringEquals, StringLike, IpAddress, ArnLike, DateLessThan, NumericGreaterThan, Bool, Null, and more
IfExists variantsStringEqualsIfExists, IpAddressIfExists, etc. - condition passes if the key is absent
Set operatorsForAllValues and ForAnyValue qualifiers for multi-valued condition keys
Identity-based policiesInline and managed policies on users, groups, and roles
Resource-based policiesS3 bucket policies, SQS queue policies, SNS topic policies, KMS key policies
Permission boundariesMaximum permissions boundary attached to users or roles

Special Rules

Root principal bypass

Requests signed with a root access key bypass all IAM checks. Default root keys are AKIAIOSFODNN7EXAMPLE and 000000000000. The awsemu CLI uses AKIAIOSFODNN7EXAMPLE by default. To add your own root key IDs, set ROOT_ACCESS_KEYS to a comma-separated list of access key IDs you want to exempt.

One unconditionally exempt action

Only sts:GetCallerIdentity is exempt from enforcement so callers can identify themselves even with no permissions. Every other action, including the rest of STS (AssumeRole, GetSessionToken) and all of IAM, is evaluated against policies.

Internal-call sentinel

LocalEmu's own cross-service calls (e.g., an S3 PutObject that triggers a Lambda, or an Event-Source-Mapping reading from SQS) bypass enforcement via an internal sentinel key. Users never produce this key, it exists so the emulator's plumbing is not blocked by user policies.

Error format

Denied requests return HTTP 403 with an AccessDenied error. The message includes the caller ARN, the attempted action, and the target resource.

ARN Building

The enforcement engine builds resource ARNs automatically for each service. This determines what the Resource field in your policy should match.

Service ARN Pattern
S3arn:aws:s3:::bucket-name/*
DynamoDBarn:aws:dynamodb:us-east-1:000000000000:table/name
Lambdaarn:aws:lambda:us-east-1:000000000000:function:name
SQSarn:aws:sqs:us-east-1:000000000000:queue-name
SNSarn:aws:sns:us-east-1:000000000000:topic-name
KMSarn:aws:kms:us-east-1:000000000000:key/key-id
IAMarn:aws:iam::000000000000:user/name
EC2arn:aws:ec2:us-east-1:000000000000:instance/i-id
CloudFormationarn:aws:cloudformation:us-east-1:000000000000:stack/name/uuid
CloudWatch Logsarn:aws:logs:us-east-1:000000000000:log-group:name
Secrets Managerarn:aws:secretsmanager:us-east-1:000000000000:secret:name
SSMarn:aws:ssm:us-east-1:000000000000:parameter/name
Step Functionsarn:aws:states:us-east-1:000000000000:stateMachine:name
EventBridgearn:aws:events:us-east-1:000000000000:rule/name
Kinesisarn:aws:kinesis:us-east-1:000000000000:stream/name
API Gatewayarn:aws:apigateway:us-east-1::/restapis/id

Example: Create User, Attach Policy, Verify

Step 1: Create an IAM user with access keys

Terminal
$ awsemu iam create-user --user-name dev
$ awsemu iam create-access-key --user-name dev

AccessKeyId: AKIA_DEV_KEY
SecretAccessKey: dev_secret_key

Step 2: Attach an inline policy allowing S3 read access

Terminal
$ awsemu iam put-user-policy \
    --user-name dev \
    --policy-name s3-read \
    --policy-document '{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["s3:GetObject", "s3:ListBucket"],
    "Resource": [
      "arn:aws:s3:::my-bucket",
      "arn:aws:s3:::my-bucket/*"
    ]
  }]
}'

Step 3: List objects succeeds (s3:ListBucket is allowed)

Terminal
$ AWS_ACCESS_KEY_ID=AKIA_DEV_KEY \
  AWS_SECRET_ACCESS_KEY=dev_secret_key \
  awsemu s3 ls s3://my-bucket/

2026-04-10 12:00:00  1024 file.txt

Step 4: Delete object fails (s3:DeleteObject is not in the policy)

Terminal
$ AWS_ACCESS_KEY_ID=AKIA_DEV_KEY \
  AWS_SECRET_ACCESS_KEY=dev_secret_key \
  awsemu s3 rm s3://my-bucket/file.txt

An error occurred (AccessDenied): User arn:aws:iam::000000000000:user/dev
is not authorized to perform s3:DeleteObject on resource
arn:aws:s3:::my-bucket/file.txt

Resource-Based Policies

Services like S3, SQS, SNS, and KMS support resource-based policies. These are evaluated alongside identity-based policies during the enforcement check.

Terminal
# S3 bucket policy allowing cross-account access
$ awsemu s3api put-bucket-policy \
    --bucket shared-data \
    --policy '{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"AWS": "arn:aws:iam::000000000000:user/reader"},
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::shared-data/*"
  }]
}'