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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4730caf1da0213c4e6db4a0e5d0bee7d8f552099949b3d9cd9371dc867ebfc51
|
|
| MD5 |
ab1afab8ee57860aa13dead9553304f0
|
|
| BLAKE2b-256 |
141ca4342461d9c809627f7d217af3738e1463ffd425a2b0671415e0eb8c4b6f
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b34c4b971d482fcf4e6443d4de5432c24405d5d28bab8c43c67d6f56d923d36
|
|
| MD5 |
70141cd70d87c73cbecbc5e22f1e8d6f
|
|
| BLAKE2b-256 |
943a210839b1fb97cbac881e61b63c63bac7092c9eb706994f3fa98f2c0ceac8
|