Skip to main content

Validate AWS IAM policies for correctness and security using AWS Service Reference API

Project description

IAM Policy Validator

Stop IAM misconfigurations before they become breaches — Catch overprivileged permissions, dangerous wildcards, and policy errors before deployment.

GitHub Actions Python 3.10+ License: MIT OpenSSF Scorecard

Full Documentation


Table of Contents


Why This Tool Exists

Security teams need to enforce organization-specific IAM requirements and catch dangerous patterns before policies reach production. Manual review doesn't scale, and AWS's built-in validation in IAM console only checks more syntax and less security.

Real problems this detects:

  1. Privilege escalation chains - Scattered actions that together grant admin access
  2. Broken automation - Syntactically valid but functionally wrong policies (s3:GetObject on bucket ARN)
  3. Missing security controls - No IAM conditions for sensitive AWS API actions
  4. Overly permissive access - Wildcard actions and resources that violate least privilege
  5. Trust policy vulnerabilities - Confused deputy risks, incorrect principals, missing OIDC audience, SAML misconfiguration
  6. Typos and invalid syntax - Invalid actions (s3:GetObjekt), condition keys, or ARN formats before deployment
  7. Your own detection - Set custom configuration file for custom detections

Quick Start

pip install iam-policy-validator

# Try it with the example policies (from repository root)
iam-validator validate --path examples/quick-start/ --format enhanced
See the example policies used (examples/quick-start/)

user-policy.json - Contains typo and missing condition:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObjekt",
      "Resource": "arn:aws:s3:::my-bucket/*"
    },
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/lambda-role"
    }
  ]
}

s3-policy.json - Sensitive action without conditions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

lambda-policy.json - Valid policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
    }
  ]
}
See the example output
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                  │
│                                  IAM Policy Validation Report                                    │
│                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
───────────────────────────────────────── Detailed Results ─────────────────────────────────────────
❌ [1/3] examples/quick-start/user-policy.json • INVALID (IAM errors + security issues)
     2 issue(s) found

Issues (2)
├── 🔴 High
│   └── [Statement 2 @L10] missing_required_condition
│       └── Required: Action(s) `iam:PassRole` require condition `iam:PassedToService`
│           ├── Action: iam:PassRole • Condition: iam:PassedToService
│           └── 💡 Restrict which AWS services can assume the passed role to prevent privilege escalation
│               Example:
│               "Condition": {
│                 "StringEquals": {
│                   "iam:PassedToService": [
│                     "lambda.amazonaws.com",
│                     "ecs-tasks.amazonaws.com",
│                     "ec2.amazonaws.com",
│                     "glue.amazonaws.com"
│                   ]
│                 }
│               }
└── 🔴 Error
    └── [Statement 1 @L5] invalid_action
        └── Action `GetObjekt` not found in service `s3`.
            └── Action: s3:GetObjekt

❌ [2/3] examples/quick-start/s3-policy.json • FAILED (critical security issues)
     1 issue(s) found

Issues (1)
└── 🔴 High
    └── [Statement 1 @L5] missing_required_condition_any_of
        └── Actions `s3:GetObject` require at least ONE of these conditions: `aws:ResourceOrgID` OR
            `aws:ResourceOrgPaths` OR `aws:SourceIp` OR `aws:SourceVpc` OR `aws:SourceVpce` OR
            `aws:ResourceAccount`
            └── 💡 Add at least ONE of these conditions to restrict S3 operations
                [truncated...]

✅ [3/3] examples/quick-start/lambda-policy.json • VALID
     No issues detected

╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                  │
│  ❌ VALIDATION FAILED                                                                            │
│  2 of 3 policies have critical issues that must be resolved.                                     │
│                                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯

What Makes This Different

1. Enforce Your Organization's Security Rules

Define security requirements as code -- the validator becomes your organization's policy gatekeeper:

# .iam-validator.yaml - Your security requirements as code
action_condition_enforcement:
  enabled: true
  action_condition_requirements:
    # Require service-specific PassRole
    - actions: ["iam:PassRole"]
      required_conditions:
        - condition_key: "iam:PassedToService"
          description: "Restrict which services can use passed roles"

    # Enforce IP restrictions for privileged actions (automation from CI/CD)
    - actions:
        ["iam:AttachUserPolicy", "iam:PutUserPolicy", "iam:CreateAccessKey"]
      required_conditions:
        - condition_key: "aws:SourceIp"
          expected_value: ["10.0.0.0/8", "172.16.0.0/12"]
          description: "Only allow from corporate network or CI/CD"

    # Require encryption for S3 uploads
    - actions: ["s3:PutObject"]
      required_conditions:
        - condition_key: "s3:x-amz-server-side-encryption"
          operator: "StringEquals"
          expected_value: "AES256"

    # Enforce tagging requirements
    - actions: ["ec2:RunInstances"]
      required_conditions:
        all_of:
          - condition_key: "aws:RequestTag/CostCenter"
          - condition_key: "aws:RequestTag/Environment"
          - condition_key: "aws:RequestTag/Owner"

Why this matters: Other tools perform AWS-standard security checks but lack the flexibility to codify your organization's specific security requirements (IP restrictions, tagging mandates, encryption requirements, etc.).


2. Detect Cross-Statement Privilege Escalation

Privilege escalation often occurs when multiple actions are scattered across different statements. This validator uses all_of logic to detect when ALL actions in a dangerous combination exist somewhere in the policy:

{
  "Statement": [
    {
      "Sid": "AllowUserManagement",
      "Action": "iam:CreateUser",
      "Resource": "*"
    },
    { "Sid": "AllowS3Read", "Action": "s3:GetObject", "Resource": "*" },
    {
      "Sid": "AllowPolicyAttachment",
      "Action": "iam:AttachUserPolicy",
      "Resource": "*"
    }
  ]
}

Detected: Statements 1 and 3 enable privilege escalation -- create a new IAM user, attach AdministratorAccess, and escalate to full account access.

Built-in escalation patterns (enabled by default):

  • User privilege escalation (iam:CreateUser + iam:AttachUserPolicy)
  • Role privilege escalation (iam:CreateRole + iam:AttachRolePolicy)
  • Lambda function backdoor (lambda:CreateFunction + lambda:InvokeFunction)
  • Lambda code injection (lambda:UpdateFunctionCode + lambda:InvokeFunction)
  • Policy version manipulation (iam:CreatePolicyVersion + iam:SetDefaultPolicyVersion)
  • EC2 instance privilege escalation (ec2:RunInstances + iam:PassRole)

Additionally detects hundreds of sensitive actions across 4 categories (credential exposure, data access, privilege escalation, resource exposure) that should have IAM conditions. List of actions copied from primeharbor/sensitive_iam_actions.

See Security Checks Documentation for all built-in patterns and custom configuration.


3. Catch Functionally Broken Policies

Validates that actions and resources are compatible -- catches policies that pass AWS validation but fail at runtime:

{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::mybucket"
}

Detected: s3:GetObject operates on objects, not buckets. This policy does nothing. Fix: "Resource": "arn:aws:s3:::mybucket/*"

More action-resource mismatches this catches:

Broken Policy Problem Fix
s3:ListBucket with arn:aws:s3:::bucket/* ListBucket needs a bucket ARN, not an object ARN arn:aws:s3:::bucket
iam:ListUsers with arn:aws:iam::*:user/bob ListUsers is global, needs wildcard *
ec2:DescribeInstances with arn:aws:ec2:*:*:instance/i-1234 Describe actions don't support resource-level perms *

Why this matters: These policies look correct but fail silently in production. AWS validates syntax, not action-resource compatibility.


4. Uses Official AWS Service Definitions

Fetches real AWS service data from AWS's official IAM service definition API (JSON endpoint) -- always accurate and up-to-date:

  • Actions: Validates against 250+ AWS services with complete action lists
  • Condition keys: Checks valid keys for each action
  • Resource types: Validates ARN formats and resource compatibility
  • Auto-updating: Fetches latest definitions on-demand or use cached versions
# Query AWS service definitions (like Policy Sentry)
iam-validator query action --service s3 --access-level write
iam-validator query condition --service s3 --name s3:prefix
iam-validator query arn --service lambda --name function

# Download for offline use
iam-validator sync-services --output-dir ./aws-services
iam-validator validate --path policies/ --aws-services-dir ./aws-services

5. Built for CI/CD and Developer Workflows

GitHub PR Integration:

  • Diff-aware filtering: Only comments on lines you actually changed
  • Line-specific feedback: Inline comments on policy files with exact line numbers
  • Smart cleanup: Updates existing comments, removes stale ones
  • Severity-based reviews: Auto-approve or request changes based on findings

Multiple output formats: Console, JSON, SARIF (GitHub Code Scanning), Markdown, HTML, CSV

Example GitHub Action:

- uses: boogy/iam-policy-validator@v1
  with:
    path: policies/
    create-review: true # Inline PR comments
    github-summary: true # Actions summary tab
    config-file: .iam-validator.yaml # fail_on_severity set in config

What Does It Check?

AWS Correctness (14 checks)

Validates against official AWS IAM requirements:

Check What It Does
Policy Structure Required fields (Version, Statement, Effect), valid JSON/YAML, outdated version warnings
Action Validation Actions exist in AWS services (detects typos: s3:GetObjekt)
Condition Keys Valid condition keys for actions (e.g., s3:prefix valid for s3:ListBucket)
Condition Types Operator-value type matching (IP/CIDR format, ARN format, Bool values, type compatibility)
IfExists Validation Validates proper usage of IfExists suffix on condition operators
Resource ARNs Correct ARN format and patterns
Principal Validation Valid principals in resource/trust policies
NotPrincipal Validation Detects unsupported NotPrincipal+Allow and deprecated NotPrincipal usage patterns
Policy Size AWS limits (6144 bytes managed, 10240 inline, 20480 resource, 5120 SCP)
SID Uniqueness Statement IDs unique within policy
Set Operators Correct ForAllValues/ForAnyValue usage with arrays
MFA Conditions Detect insecure MFA patterns (!= false instead of == true)
Policy Type RCP/SCP-specific requirements (size limits, Principal/NotPrincipal restrictions)
Action-Resource Matching Actions compatible with resources (catches functional errors)

Security Best Practices (7 checks)

Identifies overly permissive configurations:

Check What It Catches
Wildcard Action Action: "*" grants all AWS permissions
Wildcard Resource Resource: "*" applies to all resources
Full Wildcard Both Action: "*" AND Resource: "*" (admin access)
Service Wildcards s3:*, iam:*, ec2:* (overly broad)
NotAction/NotResource Dangerous NotAction/NotResource patterns with implicit grants
Sensitive Actions 490+ privilege escalation patterns and dangerous actions
Condition Enforcement Organization-specific condition requirements

Note on Sensitive Actions: This check has two modes:

  • all_of: Policy-wide detection (e.g., iam:CreateUser in statement 0 + iam:AttachUserPolicy in statement 2)
  • any_of: Per-statement detection (e.g., any statement with iam:PutUserPolicy)

Trust Policy Validation (opt-in)

Specialized checks for role assumption:

  • Confused deputy detection -- flags service principals (e.g., sns.amazonaws.com) without aws:SourceArn/aws:SourceAccount conditions, with a curated safe-service list verified against AWS documentation
  • Correct principal types (AssumeRoleWithSAML needs Federated principal)
  • SAML/OIDC provider ARN validation
  • Required conditions (SAML:aud, OIDC audience)
  • Federated identity best practices

Installation & Usage

CLI

pip install iam-policy-validator

# Validate (no AWS credentials needed)
iam-validator validate --path policies/

# With AWS Access Analyzer (requires AWS credentials)
iam-validator analyze --path policies/ --run-all-checks

# Different policy types
iam-validator validate --path trust-policies/ --policy-type TRUST_POLICY

# Output formats
iam-validator validate --path policies/ --format json --output report.json
iam-validator validate --path policies/ --format sarif --output code-scanning.sarif

Python Library

from iam_validator.sdk import validate_file, validate_directory, quick_validate

# Validate a single file
result = await validate_file("policy.json")
for issue in result.issues:
    print(f"{issue.severity}: {issue.message} at line {issue.line_number}")

# Validate a directory
results = await validate_directory("./policies")
for result in results:
    if not result.is_valid:
        print(f"{result.file_path}: {len(result.issues)} issues")

# Quick one-liner validation
issues = await quick_validate("policy.json")

See the Python Library Guide for the full SDK reference.

Configuration

All checks are customizable via .iam-validator.yaml:

settings:
  enable_builtin_checks: true
  fail_on_severity: high

# Detect cross-statement privilege escalation
sensitive_action:
  enabled: true
  sensitive_actions:
    # Policy-wide: ALL actions must exist somewhere in policy
    - all_of:
        - "iam:CreateUser"
        - "iam:AttachUserPolicy"
    - all_of:
        - "lambda:CreateFunction"
        - "iam:PassRole"

    # Per-statement: ANY action in a single statement
    - any_of:
        - "iam:PutUserPolicy"
        - "iam:PutGroupPolicy"

# Enforce your organization's conditions
action_condition_enforcement:
  enabled: true
  action_condition_requirements:
    - actions: ["iam:PassRole"]
      required_conditions:
        - condition_key: "iam:PassedToService"

    # IP restrictions for admin actions (automation from CI/CD IPs)
    - actions: ["iam:CreateUser", "iam:DeleteUser", "iam:CreateAccessKey"]
      required_conditions:
        - condition_key: "aws:SourceIp"
          expected_value: ["10.0.0.0/8", "52.94.76.0/24"] # Corporate + GitHub Actions

# Ignore patterns
ignore_patterns:
  - filepath: "terraform/modules/admin/*.json"
    reason: "Admin policies reviewed separately"

For the full configuration reference including how action_condition_enforcement and sensitive_action work together, see:


MCP Server

Use the IAM Policy Validator as an MCP server for AI assistants like Claude Desktop. Provides 36 tools across validation, policy generation, AWS service querying, analysis, and organization config management.

# Quick start with uvx (no installation needed)
uvx --from "iam-policy-validator[mcp]" iam-validator-mcp

# Or install with MCP extras
pip install "iam-policy-validator[mcp]"
iam-validator-mcp

See the MCP Server Documentation for Claude Desktop configuration and tool reference.


AWS Access Analyzer (Optional)

Optionally enable AWS Access Analyzer to validate policy syntax, then perform security checks on top of that validation:

# Check for public access (S3, SNS, SQS, etc.)
iam-validator analyze --path bucket-policy.json \
  --policy-type RESOURCE_POLICY \
  --check-no-public-access \
  --public-access-resource-type "AWS::S3::Bucket"

# Prevent specific actions
iam-validator analyze --path policy.json \
  --check-access-not-granted "s3:DeleteBucket iam:DeleteUser"

# Compare against baseline (detect permission creep)
iam-validator analyze --path new-policy.json \
  --check-no-new-access baseline-policy.json

Note: Access Analyzer requires AWS credentials. Built-in checks work offline.


Comparison with Other Tools

Feature IAM Policy Validator Policy Sentry IAM Lens IAMSpy
Primary Purpose Pre-deployment validation Least-privilege generation Runtime permission analysis Permission enumeration
Use Case CI/CD policy scanning Policy creation "What can this principal do?" Pentesting/audit
Custom Security Rules Full support No No No
Cross-Statement Patterns Privilege escalation detection N/A N/A N/A
Action-Resource Validation Catches incompatible pairs Generates correct pairs N/A No
Organization Conditions IP, tags, encryption, etc. No No No
CI/CD Ready GitHub Actions native Manual setup Manual setup Manual
PR Line Comments Diff-aware No No No
AWS Service Data Official API (auto-update) Official API Real AWS account data Static
Offline Mode Yes Needs internet Needs AWS account Yes
Query Permissions Yes Excellent Yes (different approach) Enumerate only

These tools are complementary, not competing. Choose based on your use case:

  • This tool -- Pre-deployment CI/CD validation with custom security rules and PR integration
  • Policy Sentry -- Generate least-privilege policies from scratch (great for policy creation)
  • IAM Lens -- Runtime permission analysis and request simulation (great for understanding existing permissions)
  • IAMSpy -- Enumerate existing permissions in AWS accounts (security assessment/pentesting)
  • Parliament -- Basic IAM policy linting (this tool extends Parliament's ARN pattern matching)
  • Cloudsplaining -- Scan existing AWS account policies for security issues (runtime audit)
  • AWS Access Analyzer -- AWS's built-in validation and external access detection (this tool can optionally integrate with it)

Documentation


Contributing

Contributions welcome! See CONTRIBUTING.md.

git clone https://github.com/boogy/iam-policy-validator.git
cd iam-policy-validator
uv sync --extra dev
uv run pytest

License

MIT License - see LICENSE.

  • Third-party code: ARN pattern matching derived from Parliament (BSD 3-Clause).

Support

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

iam_policy_validator-1.18.2.tar.gz (767.4 kB view details)

Uploaded Source

Built Distribution

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

iam_policy_validator-1.18.2-py3-none-any.whl (424.7 kB view details)

Uploaded Python 3

File details

Details for the file iam_policy_validator-1.18.2.tar.gz.

File metadata

  • Download URL: iam_policy_validator-1.18.2.tar.gz
  • Upload date:
  • Size: 767.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for iam_policy_validator-1.18.2.tar.gz
Algorithm Hash digest
SHA256 15f2bfe932f294ca42b2d3f9888da6d0d7397632894906870c596c72724a0dad
MD5 4586c9c122520565fcd66edb33ed2305
BLAKE2b-256 056324a7fc2f181f0417cf13b49df0ab33d7ecea5c60b7fec9bdd0744fb274d3

See more details on using hashes here.

File details

Details for the file iam_policy_validator-1.18.2-py3-none-any.whl.

File metadata

  • Download URL: iam_policy_validator-1.18.2-py3-none-any.whl
  • Upload date:
  • Size: 424.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.0 {"installer":{"name":"uv","version":"0.11.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for iam_policy_validator-1.18.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b68761b728a59b0cb7ebd6c8f1a1262d81918809d038964ac682358552cdbced
MD5 d6ad90a3bff00b158319d4ba01940517
BLAKE2b-256 c367f7960c8890ae083e04172707907db866c75a3595922efbd1a7f93d2aa5dc

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