I Tried Out "PolicyExclusionList," a New Feature of IAM Policy Simulator

I Tried Out "PolicyExclusionList," a New Feature of IAM Policy Simulator

The new PolicyExclusionList parameter in IAM Policy Simulator lets you simulate access with specific policies hypothetically excluded. I tested "what if I remove this Deny policy?" with multiple blockers and resource-based policies.
2026.08.01

This page has been translated by machine translation. View original

Introduction

On July 30, 2026, there was an update to the IAM Policy Simulator, along with its integration into the console.

https://aws.amazon.com/about-aws/whats-new/2026/07/iam-policy-simulator-iam-console/

Of the added features, PolicyExclusionList is a parameter that lets you run a simulation with specified policies excluded from evaluation. Is it safe to delete a certain Deny policy? Even if you delete it, would another blocker still stop the request? Previously, you couldn't know until you actually deleted it. With this parameter, you can estimate the impact before deleting. In this article, I gradually increased the number of excluded targets and tracked how the evaluation results changed.

Verification

Verification environment setup

For the IAM user used in the verification, I prepared one source of permission and two blockers for s3:GetObject.

Element Content Role for s3:GetObject
Managed policy ReadOnlyAccess (AWS managed) Allows s3:GetObject Source of permission
Inline policy DenyS3GetObject Explicitly denies s3:GetObject Blocker 1
Permissions Boundary cm-simulator-exclusion-boundary (customer managed) Allows only s3:ListBucket / s3:ListAllMyBuckets Blocker 2 (does not allow s3:GetObject = implicit Deny)

Running a simulation requires the iam:SimulatePrincipalPolicy permission.

Basic simulation (no exclusions)

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:user/cm-simulator-exclusion-test-user \
  --action-names s3:GetObject \
  --resource-arns "arn:aws:s3:::cm-simulator-test-bucket/*"
  • EvalDecision: explicitDeny
  • MatchedStatements: user_cm-simulator-exclusion-test-user_DenyS3GetObject
  • PermissionsBoundaryDecisionDetail: {"AllowedByPermissionsBoundary": false}

EvalDecision indicates whether the action is allowed, and MatchedStatements indicates the policy that affected that decision. Here, the explicit Deny in the inline policy matched, and this is Blocker 1.

Note that the bucket specified in --resource-arns does not need to actually exist.

Excluding the blockers one at a time

Each element of PolicyExclusionList is a union structure (PolicyIdentifier). You specify exactly one of PolicyType / PolicyArn / InlinePolicyIdentifier. InlinePolicyIdentifier, used to specify an inline policy, requires all three fields: PolicyName, AttachmentType, and AttachmentName.

Let's exclude only the inline policy DenyS3GetObject. If the explicit Deny disappears, it seems the Allow in ReadOnlyAccess would go through, but the result was different.

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:user/cm-simulator-exclusion-test-user \
  --action-names s3:GetObject \
  --resource-arns "arn:aws:s3:::cm-simulator-test-bucket/*" \
  --policy-exclusion-list '[{"InlinePolicyIdentifier":{"PolicyName":"DenyS3GetObject","AttachmentType":"user","AttachmentName":"cm-simulator-exclusion-test-user"}}]'
  • EvalDecision: implicitDeny
  • MatchedStatements: empty
  • PermissionsBoundaryDecisionDetail: {"AllowedByPermissionsBoundary": false}

EvalDecision changed from explicitDeny to implicitDeny, so the exclusion of the explicit Deny worked. However, because there are multiple blockers, excluding just one does not result in allowed. At this point MatchedStatements is empty, and ReadOnlyAccess, which was not excluded, does not appear either, so the cause cannot be read from it. The cause is that PermissionsBoundaryDecisionDetail remains false. The Permissions Boundary of Blocker 2 does not allow s3:GetObject.

Next, let's exclude the Permissions Boundary as well.

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:user/cm-simulator-exclusion-test-user \
  --action-names s3:GetObject \
  --resource-arns "arn:aws:s3:::cm-simulator-test-bucket/*" \
  --policy-exclusion-list '[{"InlinePolicyIdentifier":{"PolicyName":"DenyS3GetObject","AttachmentType":"user","AttachmentName":"cm-simulator-exclusion-test-user"}},{"PolicyType":"permission-boundary"}]'
  • EvalDecision: allowed
  • MatchedStatements: ReadOnlyAccess (IAM Policy)

Specifying permission-boundary for PolicyType excludes the entire attached Permissions Boundary. Both blockers are now removed, and the result is allowed.

When resource-based policies are involved

Simulations that include resource-based policies are supported only for IAM users (SimulatePrincipalPolicy).

Exclude all three identity-side items (ReadOnlyAccess, DenyS3GetObject, and the Permissions Boundary). Instead, grant permission through a resource-based policy (bucket policy) using --resource-policy.

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:user/cm-simulator-exclusion-test-user \
  --action-names s3:GetObject \
  --resource-arns "arn:aws:s3:::cm-simulator-test-bucket/*" \
  --policy-exclusion-list '[{"InlinePolicyIdentifier":{"PolicyName":"DenyS3GetObject","AttachmentType":"user","AttachmentName":"cm-simulator-exclusion-test-user"}},{"PolicyType":"permission-boundary"},{"PolicyArn":"arn:aws:iam::aws:policy/ReadOnlyAccess"}]' \
  --resource-policy '{"Version":"2012-10-17","Statement":[{"Sid":"AllowUserGetObject","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:user/cm-simulator-exclusion-test-user"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::cm-simulator-test-bucket/*"}]}'
  • EvalDecision: allowed
  • MatchedStatements: ResourcePolicy (SourcePolicyType: Resource Policy)

This allowed is due solely to the Allow in the resource-based policy. When I removed only --resource-policy while leaving the exclusions unchanged, the result was implicitDeny and MatchedStatements was also empty. Since no identity-side permissions remain, there is no reason it passed other than the resource-based policy.

Summary

The policies that can be excluded with PolicyExclusionList are of five types: inline policies, AWS managed policies, customer managed policies, Permissions Boundaries, and SCPs. What I tested this time were the exclusion of an inline policy, an AWS managed policy, and a Permissions Boundary, as well as the evaluation of a resource-based policy provided via --resource-policy. I did not test configurations that include SCPs.

In a configuration with multiple blockers, excluding just one explicit Deny left the result at implicitDeny, and it became allowed only after the Permissions Boundary was also removed. With PolicyExclusionList, you can isolate this question of "how much do I need to remove for it to pass?" step by step, before touching any policies.

Share this article

AWSのお困り事はクラスメソッドへ