Skip to main content

IAM Policy Analyzer & Fixer

Project description

iamarmor

ESLint for AWS IAM — catch over-permissioned policies in your Terraform PRs before they merge.

PyPI version Python versions CI License: MIT


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 linter for Terraform IAM resources. It runs entirely offline — no AWS credentials, no Terraform plan needed — and integrates as a pre-commit hook or a CI step in seconds. Think ESLint, but for your IAM policies.

$ iamarmor lint 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

iamarmor demo

Regenerate with: vhs docs/demo.tape


Quickstart

# Install (requires Python 3.11+)
pip install iamarmor

# Lint the current directory
iamarmor lint .

# Lint a specific file
iamarmor lint modules/iam/main.tf

# Machine-readable output for CI pipelines
iamarmor lint . --format json

iamarmor lint 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 linted path (same pattern as .eslintrc). 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.1.1
    hooks:
      - id: iamarmor

See docs/pre-commit.md for details.


GitHub Actions CI

Add to your workflow to lint Terraform in every PR:

- name: Lint IAM policies
  run: |
    pip install iamarmor
    iamarmor lint . --fail-on high

Or pin a specific version:

- name: Lint IAM policies
  run: |
    pip install iamarmor==0.1.1
    iamarmor lint 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 lint against the bundled tests/fixtures/ directory.


Roadmap

iamarmor (this repo) is the OSS linter 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

iamarmor-0.1.1.tar.gz (43.0 kB view details)

Uploaded Source

Built Distribution

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

iamarmor-0.1.1-py3-none-any.whl (22.9 kB view details)

Uploaded Python 3

File details

Details for the file iamarmor-0.1.1.tar.gz.

File metadata

  • Download URL: iamarmor-0.1.1.tar.gz
  • Upload date:
  • Size: 43.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for iamarmor-0.1.1.tar.gz
Algorithm Hash digest
SHA256 8c7a9f9186d38befe424aef0ea663ed2771159397c5badd6d7dfc29fd112d158
MD5 c1a3ae27e1f3385c8175f9bc1a777323
BLAKE2b-256 d7bb76c9ced46ef1794a8d6a70b0a9f08b3138b73f4ec0d855ffe1af1980b321

See more details on using hashes here.

Provenance

The following attestation bundles were made for iamarmor-0.1.1.tar.gz:

Publisher: publish.yml on iam-armor/iamarmor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file iamarmor-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: iamarmor-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 22.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for iamarmor-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9f4c68142db325dec73b4046908a423110182b239f54869243f618f7b0b50926
MD5 30b3d1085f56d084ca6c6bd6b67a1ad8
BLAKE2b-256 b44a0e8fd406e0806fd8653106b5530fe3f3ff679f8c6b3af2e2e969b0b6999a

See more details on using hashes here.

Provenance

The following attestation bundles were made for iamarmor-0.1.1-py3-none-any.whl:

Publisher: publish.yml on iam-armor/iamarmor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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