Back to Articles

Parliament: Catching IAM Policy Mistakes Before AWS Does

[ View on GitHub ]

Parliament: Catching IAM Policy Mistakes Before AWS Does

Hook

Every AWS developer has fat-fingered an IAM policy—maybe you wrote s3:GetObjects instead of s3:GetObject, or paired ec2:TerminateInstances with a CloudWatch Logs ARN. The AWS Console catches these immediately, but your Terraform code won't know until deployment fails in production.

Context

IAM policies are deceptively tricky. They look like simple JSON, but behind the scenes they're governed by thousands of rules: which actions exist in which services, what ARN patterns each action requires, which condition keys are valid for specific operations. AWS maintains this sprawling matrix of constraints, and the IAM Console validates policies against it in real-time. But if you're managing infrastructure as code—storing policies in Git, generating them programmatically, or templating them with Terraform—you lose that validation safety net until deployment time.

This gap becomes painful at scale. Organizations managing hundreds of IAM policies across dozens of repositories need validation at code review time, not during deployment. They need to enforce custom rules like "no policies may grant access to the legacy-prod-data bucket" or "all Lambda execution roles must include specific tags." Duo Labs built Parliament to solve exactly this: it extracts the IAM validation logic from AWS, packages it as a Python library, and makes it pluggable so teams can layer their own security rules on top.

Technical Insight

Analysis Engine

Human

Machine

IAM Policy JSON

Policy Parser

Syntax Validator

iam_definition.json

AWS Actions DB

Action/Resource

Cross-Reference Engine

config.yaml

Severity Rules

Core Auditors

Custom Plugin

Auditors

Findings Aggregator

Output Format

Text Report

JSON Results

System architecture — auto-generated

Parliament's architecture centers on iam_definition.json, a 4MB database that catalogs every AWS service action, its required resource types, valid condition keys, and dependency relationships. When you run Parliament on a policy, it parses the JSON, extracts each statement's actions and resources, then cross-references them against this database to identify mismatches.

Here's a simple example of Parliament catching a common mistake:

from parliament import analyze_policy_string
import json

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

findings = analyze_policy_string(json.dumps(policy))
for finding in findings:
    print(f"{finding.severity}: {finding.title}")
    print(f"  {finding.description}")

This outputs: MEDIUM: Resource mismatch - The action 's3:GetObject' requires a resource pattern like 'arn:aws:s3:::bucket/*' but the policy specifies 'arn:aws:s3:::my-bucket'. The bucket ARN is valid for s3:ListBucket, but object operations need the /* suffix. Parliament knows this because its IAM definition maps each action to required resource patterns.

The real power comes from custom auditors. Say your organization forbids direct access to a sensitive S3 bucket. You can write a plugin:

from parliament import Auditor, Finding, Issue

class ForbiddenBucketAuditor(Auditor):
    def audit(self, policy):
        findings = []
        forbidden_buckets = ['company-secrets', 'prod-pii-data']
        
        for statement in policy.get('Statement', []):
            if statement.get('Effect') == 'Allow':
                resources = statement.get('Resource', [])
                if isinstance(resources, str):
                    resources = [resources]
                
                for resource in resources:
                    for bucket in forbidden_buckets:
                        if f'arn:aws:s3:::{bucket}' in resource:
                            findings.append(Finding(
                                issue=Issue.CUSTOM,
                                title='Forbidden bucket access',
                                description=f'Policy grants access to {bucket}',
                                severity='HIGH',
                                location={'resource': resource}
                            ))
        return findings

Parliament loads these auditors via configuration, running them alongside built-in checks. This plugin architecture lets security teams codify institutional knowledge—"we never grant iam:PassRole without condition keys" or "Lambda functions must use specific KMS keys"—rather than relying on manual code review.

The configuration system uses YAML to customize behavior. You can suppress specific findings with regex patterns, adjust severity levels, or disable entire check categories:

AWS_MANAGED_POLICIES:
  ignore_locations:
    - filepath: "terraform/legacy/*"
      reason: "Legacy module, will refactor in Q2"

RESOURCE_MISMATCH:
  severity: HIGH  # Elevate from default MEDIUM

ignore_findings:
  - action: "s3:GetObject"
    resource: "arn:aws:s3:::logs-*/*"
    reason: "All services can read from logs buckets"

Parliament can analyze policies from multiple sources: individual JSON files, directories of policies, AWS's repository of managed policies, or authorization details extracted from a live AWS account via aws iam get-account-authorization-details. This last option is particularly useful for auditing existing accounts—you can snapshot all IAM policies, roles, and groups, then run Parliament against them to identify technical debt.

The library maintains backward compatibility by versioning its IAM definition database. When AWS introduces new services or actions, Parliament updates iam_definition.json, but you can pin to specific versions if you need deterministic builds. The database itself is generated from AWS documentation using scrapers, though Duo Labs doesn't publish these tools—they release periodic database updates instead.

Gotcha

Parliament's biggest limitation is its IAM definition database going stale. AWS releases new services and actions constantly, and Parliament's database requires manual updates from maintainers. If you're using bleeding-edge AWS services, Parliament might not recognize legitimate actions or resource patterns, generating false positives. The repository's update cadence has slowed—recent commits suggest less frequent maintenance than during initial development.

More fundamentally, Parliament focuses on syntactic correctness, not semantic security. It verifies that s3:GetObject is paired with an object ARN, but it won't tell you that Resource: "*" creates a security risk. It can't detect privilege escalation paths (like combining iam:CreateAccessKey with iam:AttachUserPolicy), overly permissive principals, or missing condition keys that would restrict access. These higher-order security analyses require different tools like Cloudsplaining or manual review. Parliament is a linter, not a comprehensive security analyzer—it catches typos and structural errors, not architectural flaws.

Custom auditor documentation is sparse. The repository includes a basic example, but understanding Parliament's internal policy representation and writing robust auditors requires reading source code. There's no plugin gallery or community-contributed auditor library, so each organization builds from scratch.

Verdict

Use if: You manage IAM policies as code across multiple repositories and need automated validation in CI/CD pipelines. You want to enforce organization-specific security rules beyond AWS's built-in validation. You're working with established AWS services where Parliament's database is current. You need to audit large numbers of existing policies programmatically. Skip if: You only occasionally write policies and the AWS Console's validator suffices. You need cutting-edge AWS service support the day features launch. You require advanced security analysis like privilege escalation detection or least-privilege recommendations—Parliament won't catch these. You want a maintained, actively developed tool with guaranteed AWS coverage—the project's maintenance velocity has decreased and may not keep pace with AWS innovation.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/duo-labs-parliament.svg)](https://starlog.is/api/badge-click/developer-tools/duo-labs-parliament)