Skip to main content

Synopsis

python iam_audit.py --profile <profile> --role <role-name>

Required Arguments

Both arguments are mandatory. The tool will exit with an error if either is missing.
--profile
string
required
AWS CLI profile name configured in ~/.aws/credentials or ~/.aws/configThis profile must have access to the management account of your AWS Organization with permissions to:
  • organizations:ListAccounts
  • sts:AssumeRole into member accounts
Example:
python iam_audit.py --profile mgmt-prod --role IAMAuditRole
The profile name must exactly match a configured AWS CLI profile. Use aws configure list-profiles to see available profiles.
--role
string
required
Name of the IAM role to assume in each member accountThis role must:
  • Exist in all member accounts you want to audit
  • Have a trust policy allowing the management account to assume it
  • Have IAM and CloudTrail read permissions
Example:
python iam_audit.py --profile security-audit --role AWSControlTowerExecution
Role names are case-sensitive. IAMAuditRole and iamaauditrole are different roles.

Usage Examples

Basic Audit

python iam_audit.py --profile mgmt-profile --role AWSControlTowerExecution

Running from Different Directory

cd /path/to/iam-audit
python iam_audit.py --profile mgmt-profile --role IAMAuditRole

Using Python Virtual Environment

source venv/bin/activate
python iam_audit.py --profile mgmt-profile --role IAMAuditRole

Exit Codes

The script does not implement custom exit codes. Standard Python behavior applies:
Exit CodeMeaning
0Success
1Unhandled exception
2Command-line argument error (missing required flags)

Environment Variables

The tool respects standard AWS SDK environment variables:
AWS_PROFILE
string
Default AWS profile to use if --profile is not specified
The --profile flag is required by the argument parser. Setting AWS_PROFILE will not bypass this requirement.
AWS_DEFAULT_REGION
string
Default AWS region for API calls
IAM is a global service. CloudTrail queries are performed in us-east-1 regardless of this setting (hardcoded at iam_audit.py:96).
AWS_ACCESS_KEY_ID
string
AWS access key ID (not recommended; use profiles instead)
AWS_SECRET_ACCESS_KEY
string
AWS secret access key (not recommended; use profiles instead)

Output Files

The tool generates two CSV files in the current working directory:
File PatternDescription
iam_audit_report_YYYYMMDD_HHMMSS.csvIAM users, access keys, MFA status, and console access
cloudtrail_events_YYYYMMDD_HHMMSS.csvCloudTrail events for IAM user and key lifecycle tracking
Timestamp Format: YYYYMMDD_HHMMSS (e.g., 20260305_143022)
Files are created in the directory where you run the command, not where the script is located.

Standard Output

The tool prints progress and summary information to stdout:
Auditando cuenta: Production (123456789012)
Auditando cuenta: Staging (234567890123)
  Consultando CloudTrail en cuenta: Production (123456789012)
  Consultando CloudTrail en cuenta: Staging (234567890123)

Total de Access Keys encontradas: 47
Reporte exportado: iam_audit_report_20260305_143022.csv

2026-02-28 15:32:10 - CreateAccessKey - Usuario: [email protected] - Cuenta: Production
  Recursos afectados: ['AKIAIOSFODNN7EXAMPLE']
2026-03-01 09:15:43 - DeleteUser - Usuario: contractor-temp - Cuenta: Staging
  Recursos afectados: ['contractor-temp']

Total de eventos CloudTrail encontrados: 12
Reporte de eventos CloudTrail exportado: cloudtrail_events_20260305_143022.csv

Standard Error

Errors for specific accounts are printed to stdout (not stderr) and the audit continues:
Error en cuenta SandboxAccount: An error occurred (AccessDenied) when calling the AssumeRole operation
Error en CloudTrail cuenta DevAccount: An error occurred (AccessDeniedException) when calling LookupEvents operation
The tool does not stop on individual account failures. It continues auditing remaining accounts.

Required IAM Permissions

Management Account Profile

The profile specified with --profile needs:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "organizations:ListAccounts",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "arn:aws:iam::*:role/YOUR-ROLE-NAME"
    }
  ]
}

Member Account Role

The role specified with --role needs in each member account:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:ListUsers",
        "iam:ListAccessKeys",
        "iam:GetAccessKeyLastUsed",
        "iam:ListMFADevices",
        "iam:GetLoginProfile",
        "cloudtrail:LookupEvents"
      ],
      "Resource": "*"
    }
  ]
}
Trust Policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::MANAGEMENT-ACCOUNT-ID:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Session Names

The tool uses two different session names when assuming roles:
Session NameUsed ForSource Line
SecurityAuditIAM data collectioniam_audit.py:154
CloudTrailAuditCloudTrail event queriesiam_audit.py:93
Session names appear in CloudTrail logs, making it easy to identify audit activity.

Hardcoded Values

Be aware of these hardcoded values in the current version:
ValueLocationPurpose
2026-02-18iam_audit.py:137CloudTrail events start date
us-east-1iam_audit.py:96CloudTrail query region
['DeleteUser', 'DeleteAccessKey', 'DeleteLoginProfile', 'CreateAccessKey', 'CreateUser']iam_audit.py:88CloudTrail event names to query
The CloudTrail start date is hardcoded. To audit older events, you must modify the source code at line 137.

Next Steps

Running an Audit

Step-by-step guide to executing an audit

Understanding Reports

Learn how to analyze the generated CSV files

Build docs developers (and LLMs) love