Skip to content

fix(iam): parse Explainable-IAM denial logs in the policy analyzer - #87

Open
HarshCasper wants to merge 2 commits into
mainfrom
fix/explainable-iam-denials
Open

HarshCasper wants to merge 2 commits into
mainfrom
fix/explainable-iam-denials

Conversation

@HarshCasper

Copy link
Copy Markdown
Member

fix(iam): parse Explainable-IAM denial logs in the policy analyzer

Problem

localstack-iam-policy-analyzer → analyze-policies returns "No IAM Denials Found"
against current LocalStack, even when IAM enforcement is denying requests.

The log parser only matches the legacy denial line:

Request for service 's3' by principal '<arn>' for operation 'CreateBucket' denied.

Current LocalStack (2026.x, verified on 2026.9.0) emits the Explainable-IAM format:

User: arn:aws:iam::000000000000:user/test is not authorized to perform: s3:CreateBucket
on resource: arn:aws:s3:::mybucket because no identity-based policy allows the s3:CreateBucket action

Because the parser never flags these as denials, no policy is generated. This also hides
denials raised against Lambda execution roles (assumed-role principals), which only
surface in the new format.

Fix

  • src/lib/logs/log-retriever.ts: additionally detect the Explainable-IAM line and extract
    principal, action, resource and service. The legacy format still works.
  • src/lib/iam/iam-policy.logic.ts: the nearby-log resource enrichment now fills the resource
    only if the denial line did not already provide one, so the resource parsed from the new
    format is not overwritten by a stale nearby line.
  • src/lib/logs/log-retriever.iam.test.ts: new unit tests for both formats, assumed-role
    principals, object-scoped S3 ARNs, and that the DEBUG Necessary permissions ... lines are
    not misclassified as denials.

Verification

Against LocalStack 2026.9.0 with ENFORCE_IAM=1, after an app's Lambda hit AccessDenied under a
stripped role, analyze-policies now reports the denials and emits a correct least-privilege
policy for the assumed-role/<role>/<fn> principal. yarn jest green (new tests included).

Notes

  • No behaviour change for the legacy format.
  • Backward compatible: both log formats are parsed.

The IAM policy analyzer only recognised the legacy denial log line
("Request for service '..' by principal '..' for operation '..' denied.").
Current LocalStack (2026.x) emits the Explainable-IAM format instead:

  User: <principal> is not authorized to perform: <service:Action>
  on resource: <arn> because ...

so analyze-policies reported "No IAM Denials Found" and generated nothing
against a running LocalStack. This also affects denials raised for Lambda
execution roles (assumed-role principals), which only appear in the new format.

- log-retriever: detect the Explainable-IAM line (principal, action, resource,
  service) in addition to the legacy one.
- iam-policy.logic: only fall back to the nearby-log resource when the denial
  line did not already carry one, so the richer new format is not overwritten.
- tests: cover both formats, assumed-role principals, object-scoped S3 ARNs,
  and that the DEBUG 'Necessary permissions' lines are not themselves denials.
@HarshCasper
HarshCasper force-pushed the fix/explainable-iam-denials branch from 0070ace to 8a42932 Compare October 5, 2026 17:31
Actions such as dynamodb:ListTables log no "on resource:" clause, so the
Explainable IAM pattern did not match them. Make the clause optional.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant