IAM Policy Analyzer & Fixer
Project description
iamarmor
A static analyzer for AWS IAM policies in Terraform — catch over-permissioned policies before they merge.
Why iam-armor?
IAM misconfigurations are the #1 cause of AWS breaches — wildcards on Action and
Resource, forgotten AdministratorAccess attachments, and overly-permissive
assume_role_policy are easy to ship and hard to spot in code review.
iamarmor is a static analyzer for Terraform IAM resources. It runs entirely
offline — no AWS credentials and no terraform plan required — and fits cleanly
into your workflow as a pre-commit hook or CI step.
$ iamarmor scan modules/iam/
modules/iam/main.tf
✘ IAM001 [HIGH] resource 'aws_iam_policy.app' has Action: "*" — grant least-privilege actions instead.
✘ IAM005 [HIGH] resource 'aws_iam_policy.deployer' grants iam:PassRole on Resource: "*" — scope to specific role ARNs.
✘ IAM010 [HIGH] resource 'aws_iam_role_policy_attachment.admin' attaches AdministratorAccess — grant only required permissions.
3 findings (3 high, 0 medium, 0 low) in 0.12 s
exit 1
Demo
Regenerate with:
vhs docs/demo.tape
Quickstart
# Install (requires Python 3.11+)
pip install iamarmor
# Scan the current directory
iamarmor scan .
# Scan a specific file
iamarmor scan modules/iam/main.tf
# Machine-readable output for CI pipelines
iamarmor scan . --format json
iamarmor scan exits 0 when clean, 1 when findings meet the fail_on
threshold (default: medium), 2 on usage/config errors, and 3 on
internal errors — making CI integration trivial.
Configuration
Place a .iamarmor.yml in the root of your Terraform repository:
version: 1
severity_threshold: low # report findings at or above this level (default: info)
fail_on: high # exit 1 only for high/critical (default: medium)
rules:
ignore: [IAM004] # skip noisy rules for your environment
overrides:
IAM002:
severity: critical # escalate a rule's severity
paths:
exclude:
- "modules/legacy/**" # skip paths you're not ready to fix yet
iamarmor auto-discovers .iamarmor.yml by walking upward from the target path.
Pass --no-config to skip loading.
See docs/config.md for the full configuration reference.
Default rule pack
iamarmor ships with 10 default IAM rules covering the most common misconfigurations:
| ID | Name | Severity |
|---|---|---|
| IAM001 | No Action: "*" |
High |
| IAM002 | No Resource: "*" with sensitive actions |
High |
| IAM003 | No inline policies | Medium |
| IAM004 | IAM roles must set max_session_duration |
Low |
| IAM005 | No iam:PassRole with Resource: "*" |
High |
| IAM006 | No wildcard Principal in resource-based policies |
High |
| IAM007 | assume_role_policy must specify a concrete principal |
High |
| IAM008 | No NotAction in Allow statements |
Medium |
| IAM009 | No NotResource in Allow statements |
Medium |
| IAM010 | Do not attach AdministratorAccess managed policy |
High |
See STARTER_RULES.md for full documentation of each rule, including rationale, examples, and configuration options.
Pre-commit hook
Add to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/iam-armor/iamarmor
rev: v0.2.0
hooks:
- id: iamarmor
See docs/pre-commit.md for details.
GitHub Actions CI
Add to your workflow to scan Terraform in every PR:
- name: Scan IAM policies
run: |
pip install iamarmor
iamarmor scan . --fail-on high
Or pin a specific version:
- name: Scan IAM policies
run: |
pip install iamarmor==0.2.0
iamarmor scan modules/iam/ --format json > iam-findings.json
Python API
The CLI is the recommended entry point for most users. For embedding iamarmor in other tools, the Python API is also public:
from iamarmor import extract_from_directory, RuleEngine, load_default_rules
resources = extract_from_directory("path/to/terraform/")
engine = RuleEngine(rules=load_default_rules())
findings = engine.run(resources)
for finding in findings:
print(f"[{finding.rule_id}] {finding.severity.value.upper()} — {finding.message}")
Regenerating the demo GIF
The demo GIF was recorded with VHS. To regenerate it:
# Install VHS (requires Go)
go install github.com/charmbracelet/vhs@latest
# Re-record
vhs docs/demo.tape
The resulting docs/demo.gif is committed to the repository. The tape script
exercises iamarmor scan against the bundled tests/fixtures/ directory.
Roadmap
iamarmor (this repo) is the OSS static analyzer engine. The hosted GitHub App at
iamarmor.dev (coming soon) will add:
- 🔌 GitHub App with inline PR annotations
- 📦 Premium rule packs: SOC 2, PCI-DSS, HIPAA, AWS Well-Architected Security
- 📊 Findings dashboard and trend tracking
- 🔧 One-click auto-fix suggestions
Contributing
Contributions are welcome! Please open an issue before submitting a PR for new features or rules. See STARTER_RULES.md for the existing rule inventory and docs/ for design docs.
git clone https://github.com/iam-armor/iamarmor.git
cd iamarmor
pip install -e ".[dev]"
pytest
ruff check src/ tests/
License
MIT © 2026 iam-armor
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
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 iamarmor-0.2.0.tar.gz.
File metadata
- Download URL: iamarmor-0.2.0.tar.gz
- Upload date:
- Size: 43.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c01c17fab7bafe5524f3fef279d93d311304991b46ba76ad74570cd77a98d055
|
|
| MD5 |
ab3641277e01b8e5b3f00761275922aa
|
|
| BLAKE2b-256 |
3d8c1a3afc1f29124edbd2ccd8a25c5a9bdc5388f43acf8d5d54271322316d97
|
Provenance
The following attestation bundles were made for iamarmor-0.2.0.tar.gz:
Publisher:
publish.yml on iam-armor/iamarmor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iamarmor-0.2.0.tar.gz -
Subject digest:
c01c17fab7bafe5524f3fef279d93d311304991b46ba76ad74570cd77a98d055 - Sigstore transparency entry: 1552259035
- Sigstore integration time:
-
Permalink:
iam-armor/iamarmor@5781e6c8850102d3957babd6e027e817e3e23c9f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/iam-armor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5781e6c8850102d3957babd6e027e817e3e23c9f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file iamarmor-0.2.0-py3-none-any.whl.
File metadata
- Download URL: iamarmor-0.2.0-py3-none-any.whl
- Upload date:
- Size: 22.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e48ffc567215e9fd6e7a3aefe44348addc06a28fbc1a28fb29794311c40b5ddc
|
|
| MD5 |
8e6ab9288ef9d5ff716c133aee5b53db
|
|
| BLAKE2b-256 |
495afaaa94f89542f3dc8af731ed6ba9496a8982fd87bdd20045d58efc2ba476
|
Provenance
The following attestation bundles were made for iamarmor-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on iam-armor/iamarmor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iamarmor-0.2.0-py3-none-any.whl -
Subject digest:
e48ffc567215e9fd6e7a3aefe44348addc06a28fbc1a28fb29794311c40b5ddc - Sigstore transparency entry: 1552259078
- Sigstore integration time:
-
Permalink:
iam-armor/iamarmor@5781e6c8850102d3957babd6e027e817e3e23c9f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/iam-armor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5781e6c8850102d3957babd6e027e817e3e23c9f -
Trigger Event:
workflow_dispatch
-
Statement type: