I tried the new IAM Policy Simulator feature "PolicyExclusionList"

I tried the new IAM Policy Simulator feature "PolicyExclusionList"

The newly added `PolicyExclusionList` parameter in IAM Policy Simulator allows you to simulate access permissions with specific policies virtually excluded. I tested "How would permissions change if this Deny policy were removed?" in cases where there are multiple blockers preventing access and in cases involving 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/

Among the added features, PolicyExclusionList is a parameter that allows you to simulate with specified policies excluded from evaluation. Whether it would be safe to delete a certain Deny policy, or whether another blocker would still stop you even after deletion — previously, you couldn't know until you actually deleted it. By using this parameter, you can estimate the impact before deletion. In this article, I incrementally increased the exclusion targets and tracked how the evaluation results changed.

Verification Details

Verification Environment Configuration

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

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

The iam:SimulatePrincipalPolicy permission is required to run simulations.

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 or denied, and MatchedStatements shows the policies that influenced the decision. Here, the explicit Deny from the inline policy is matched, which is Blocker 1.

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

Excluding Blockers One at a Time

Each element of PolicyExclusionList has a union structure (PolicyIdentifier). You specify one of PolicyType / PolicyArn / InlinePolicyIdentifier. The InlinePolicyIdentifier, which specifies an inline policy, requires all three fields: PolicyName, AttachmentType, and AttachmentName.

Let's try excluding only the inline policy DenyS3GetObject. It might seem like removing the explicit Deny would allow the ReadOnlyAccess Allow to pass 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, confirming that the explicit Deny exclusion took effect. However, since there are multiple blockers, excluding just one is not enough to reach allowed. At this point, MatchedStatements is empty, and ReadOnlyAccess, which was not excluded, also does not appear, so the cause cannot be read from here. The cause is that PermissionsBoundaryDecisionDetail remains false. The Permissions Boundary of Blocker 2 does not allow s3:GetObject.

Next, let's also exclude the Permissions Boundary.

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. With both blockers removed, the result became allowed.

When Resource-Based Policies Are Involved

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

Let's exclude all three on the identity side (ReadOnlyAccess, DenyS3GetObject, and the Permissions Boundary). Instead, we'll grant permission via 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 result is solely due to the Allow from the resource-based policy. When --resource-policy is removed while keeping the exclusion specifications as-is, the result becomes implicitDeny and MatchedStatements also becomes empty. Since no allow remains on the identity side, the only reason it passed is the resource-based policy.

Summary

The policies that can be excluded with PolicyExclusionList are five types: inline policies, AWS-managed policies, customer-managed policies, Permissions Boundaries, and SCPs. In this verification, I tested excluding inline policies, AWS-managed policies, and Permissions Boundaries, as well as the evaluation of a resource-based policy provided via --resource-policy. I did not test configurations involving SCPs.

In a configuration with multiple blockers, excluding just one explicit Deny left the result at implicitDeny, and it only became allowed after also removing the Permissions Boundary. By using PolicyExclusionList, you can incrementally identify "how much needs to be removed before it passes" without actually making any changes to the policies.

Share this article

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

Related articles