Skip to main content

Explain AWS IAM access denials from the command line

Project description

iamwhy

Explains AWS IAM access denials from the command line. Given an IAM principal and an action that's being denied, iamwhy traces exactly why: which policy, which statement, which condition is blocking it.

Quick start

python3.11 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

iamwhy alice s3:GetObject
iamwhy arn:aws:iam::123456789012:role/MyRole ec2:TerminateInstances \
    --resource "arn:aws:ec2:us-east-1:123456789012:instance/i-abc123"

Usage

iamwhy PRINCIPAL ACTION [OPTIONS]

Arguments:
  PRINCIPAL   IAM user ARN, role ARN, STS assumed-role session ARN,
              bare username, or bare role name
  ACTION      AWS action string, e.g. s3:GetObject

Options:
  --resource TEXT       Resource ARN (default: *)
  --context KEY=VALUE   Context entry (repeatable)
  --output [text|json]  Output format (default: text)
  --profile TEXT        AWS credentials profile ($AWS_PROFILE)
  --region TEXT         AWS region ($AWS_DEFAULT_REGION)

Example output

Principal: arn:aws:iam::123456789012:user/alice
Action:    s3:GetObject
Resource:  arn:aws:s3:::my-bucket/data.csv

Verdict: DENIED (explicit deny)

Reason: An explicit Deny statement in "DenyPublicS3" overrides any Allow.

╭─ arn:aws:iam::123456789012:policy/DenyPublicS3 (IAMPolicy) ─╮
│ Statement: Sid=DenyS3Public                                  │
│   Effect:  Deny                                              │
│   Action:  s3:*                                              │
│   Resource: *                                                │
╰──────────────────────────────────────────────────────────────╯

Decision breakdown:
  DenyPublicS3         explicitDeny
  AmazonS3FullAccess   allowed

Missing context: (none)

JSON output

iamwhy alice s3:GetObject --output json | jq .cause
# "explicit_deny"

The JSON schema:

{
  "principal": "arn:...",
  "principal_type": "user",
  "action": "s3:GetObject",
  "resource": "*",
  "decision": "explicitDeny",
  "cause": "explicit_deny",
  "summary": "...",
  "orgs_blocked": false,
  "boundary_blocked": false,
  "missing_context": [],
  "blocking_policies": [{"policy_id": "...", "decision": "...", "statement": {...}}],
  "all_breakdown": [{"policy_id": "...", "decision": "..."}]
}

Cause values

Cause Description
explicit_deny A Deny statement in a policy explicitly blocks the action
implicit_deny No Allow was found; the default deny applies
scp_block An AWS Organizations SCP denies the action
permissions_boundary The principal's permissions boundary does not allow the action
missing_context A condition could not be evaluated due to absent context keys
combined Multiple of the above apply simultaneously

Exit codes

Code Meaning
0 Access allowed
1 Access denied
2 Usage error or AWS API error

Required permissions

iamwhy needs the following IAM permissions for the credentials you run it with:

{
  "Effect": "Allow",
  "Action": [
    "iam:SimulatePrincipalPolicy",
    "iam:GetUser",
    "iam:GetRole",
    "iam:GetPolicy",
    "iam:GetPolicyVersion",
    "iam:GetUserPolicy",
    "iam:GetRolePolicy",
    "iam:ListAttachedUserPolicies",
    "iam:ListUserPolicies",
    "iam:ListGroupsForUser",
    "iam:ListAttachedGroupPolicies",
    "iam:ListGroupPolicies",
    "iam:ListAttachedRolePolicies",
    "iam:ListRolePolicies"
  ],
  "Resource": "*"
}

iam:GetPolicy* and iam:List* are optional — iamwhy degrades gracefully if they are absent, showing the policy ID without the statement text.

Development

python3.11 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
coverage run -m pytest && coverage report

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

iamwhy-0.1.0.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

iamwhy-0.1.0-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file iamwhy-0.1.0.tar.gz.

File metadata

  • Download URL: iamwhy-0.1.0.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for iamwhy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4730caf1da0213c4e6db4a0e5d0bee7d8f552099949b3d9cd9371dc867ebfc51
MD5 ab1afab8ee57860aa13dead9553304f0
BLAKE2b-256 141ca4342461d9c809627f7d217af3738e1463ffd425a2b0671415e0eb8c4b6f

See more details on using hashes here.

File details

Details for the file iamwhy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: iamwhy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for iamwhy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4b34c4b971d482fcf4e6443d4de5432c24405d5d28bab8c43c67d6f56d923d36
MD5 70141cd70d87c73cbecbc5e22f1e8d6f
BLAKE2b-256 943a210839b1fb97cbac881e61b63c63bac7092c9eb706994f3fa98f2c0ceac8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page