Skip to main content
Prowler offers an automated tool to discover and provision all AWS accounts within an AWS Organization. This streamlines onboarding for organizations managing multiple AWS accounts by automatically generating the configuration needed for bulk provisioning. The tool, aws_org_generator.py‎, complements the Bulk Provider Provisioning tool and is available in the Prowler repository at: util/prowler-bulk-provisioning
Native support for bulk provisioning AWS Organizations and similar multi-account structures directly in the Prowler UI/API is on the official roadmap.Track progress and vote for this feature at: Bulk Provisioning in the UI/API for AWS Organizations

Overview

The AWS Organizations Bulk Provisioning tool simplifies multi-account onboarding by:
  • Automatically discovering all active accounts in an AWS Organization
  • Generating YAML configuration files for bulk provisioning
  • Supporting account filtering and custom role configurations
  • Eliminating manual entry of account IDs and role ARNs

Prerequisites

Requirements

  • Python 3.7 or higher
  • AWS credentials with Organizations read access
  • ProwlerRole (or custom role) deployed across all target accounts
  • Prowler API key (from Prowler Cloud or self-hosted Prowler App)

Deploying ProwlerRole Across AWS Organizations

Before using the AWS Organizations generator, deploy the ProwlerRole across all accounts in the organization using CloudFormation StackSets.
Follow the official documentation: Deploying Prowler IAM Roles Across AWS OrganizationsKey points:
  • Use CloudFormation StackSets from the management account
  • Deploy to all organizational units (OUs) or specific OUs
  • Use an external ID for enhanced security
  • Ensure the role has necessary permissions for Prowler scans

Installation

Clone the repository and install required dependencies:
git clone https://github.com/prowler-cloud/prowler.git
cd prowler/util/prowler-bulk-provisioning
pip install -r requirements-aws-org.txt

AWS Credentials Setup

Configure AWS credentials with Organizations read access:
  • Management account credentials, or
  • Delegated administrator account with organizations:ListAccounts permission
Required IAM permissions:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "organizations:ListAccounts",
        "organizations:DescribeOrganization"
      ],
      "Resource": "*"
    }
  ]
}

Prowler API Key Setup

Configure your Prowler API key:
export PROWLER_API_KEY="pk_example-api-key"
To create an API key:
  1. Log in to Prowler Cloud or Prowler App
  2. Click ProfileAccount
  3. Click Create API Key
  4. Provide a descriptive name and optionally set an expiration date
  5. Copy the generated API key (it will only be shown once)
For detailed instructions, see: Prowler App API Keys

Basic Usage

Generate Configuration for All Accounts

To generate a YAML configuration file for all active accounts in the organization:
python aws_org_generator.py -o aws-accounts.yaml --external-id prowler-ext-id-2024
This command:
  1. Lists all ACTIVE accounts in the organization
  2. Generates YAML entries for each account
  3. Saves the configuration to aws-accounts.yaml
Output:
Fetching accounts from AWS Organizations...
Found 47 active accounts in organization
Generated configuration for 47 accounts

Configuration written to: aws-accounts.yaml

Next steps:
  1. Review the generated file: cat aws-accounts.yaml | head -n 20
  2. Run bulk provisioning: python prowler_bulk_provisioning.py aws-accounts.yaml

Review Generated Configuration

Review the generated YAML configuration:
head -n 20 aws-accounts.yaml
Example output:
- provider: aws
  uid: '111111111111'
  alias: Production-Account
  auth_method: role
  credentials:
    role_arn: arn:aws:iam::111111111111:role/ProwlerRole
    external_id: prowler-ext-id-2024

- provider: aws
  uid: '222222222222'
  alias: Development-Account
  auth_method: role
  credentials:
    role_arn: arn:aws:iam::222222222222:role/ProwlerRole
    external_id: prowler-ext-id-2024

Dry Run Mode

Test the configuration without writing a file:
python aws_org_generator.py \
  --external-id prowler-ext-id-2024 \
  --dry-run

Advanced Configuration

Using a Specific AWS Profile

Specify an AWS profile when multiple profiles are configured:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --profile org-management-admin \
  --external-id prowler-ext-id-2024

Excluding Specific Accounts

Exclude the management account or other accounts from provisioning:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --external-id prowler-ext-id-2024 \
  --exclude 123456789012,210987654321
Common exclusion scenarios:
  • Management account (requires different permissions)
  • Break-glass accounts (emergency access)
  • Suspended or archived accounts

Including Only Specific Accounts

Generate configuration for specific accounts only:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --external-id prowler-ext-id-2024 \
  --include 111111111111,222222222222,333333333333

Custom Role Name

Specify a custom role name if not using the default ProwlerRole:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --role-name ProwlerExecutionRole \
  --external-id prowler-ext-id-2024

Custom Alias Format

Customize account aliases using template variables:
# Use account name and ID
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --alias-format "{name}-{id}" \
  --external-id prowler-ext-id-2024

# Use email prefix
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --alias-format "{email}" \
  --external-id prowler-ext-id-2024
Available template variables:
  • {name} - Account name
  • {id} - Account ID
  • {email} - Account email

Additional Role Assumption Options

Configure optional role assumption parameters:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --role-name ProwlerRole \
  --external-id prowler-ext-id-2024 \
  --session-name prowler-scan-session \
  --duration-seconds 3600

Complete Workflow Example

1

Deploy ProwlerRole Using StackSets

  1. Log in to the AWS management account
  2. Open CloudFormation → StackSets
  3. Create a new StackSet using the Prowler role template
  4. Deploy to all organizational units
  5. Use a unique external ID (e.g., prowler-org-2024-abc123)
2

Generate YAML Configuration

Configure AWS credentials and generate the YAML file:
# Using management account credentials
export AWS_PROFILE=org-management

# Generate configuration
python aws_org_generator.py \
  -o aws-org-accounts.yaml \
  --external-id prowler-org-2024-abc123 \
  --exclude 123456789012
Output:
Fetching accounts from AWS Organizations...
Using AWS profile: org-management
Found 47 active accounts in organization
Generated configuration for 46 accounts

Configuration written to: aws-org-accounts.yaml

Next steps:
  1. Review the generated file: cat aws-org-accounts.yaml | head -n 20
  2. Run bulk provisioning: python prowler_bulk_provisioning.py aws-org-accounts.yaml
3

Review Generated Configuration

Verify the generated YAML configuration:
# View first 20 lines
head -n 20 aws-org-accounts.yaml

# Check for unexpected accounts
grep "uid:" aws-org-accounts.yaml

# Verify role ARNs
grep "role_arn:" aws-org-accounts.yaml | head -5

# Count accounts
grep "provider: aws" aws-org-accounts.yaml | wc -l
4

Run Bulk Provisioning

Provision all accounts to Prowler Cloud or Prowler App:
# Set Prowler API key
export PROWLER_API_KEY="pk_example-api-key"

# Run bulk provisioning with connection testing
python prowler_bulk_provisioning.py aws-org-accounts.yaml
With custom options:
python prowler_bulk_provisioning.py aws-org-accounts.yaml \
  --concurrency 10 \
  --timeout 120
Successful output:
[1] ✅ Created provider (id=db9a8985-f9ec-4dd8-b5a0-e05ab3880bed)
[1] ✅ Created secret (id=466f76c6-5878-4602-a4bc-13f9522c1fd2)
[1] ✅ Connection test: Connected

[2] ✅ Created provider (id=7a99f789-0cf5-4329-8279-2d443a962676)
[2] ✅ Created secret (id=c5702180-f7c4-40fd-be0e-f6433479b126)
[2] ✅ Connection test: Connected

Done. Success: 47  Failures: 0

Command Reference

Full Command-Line Options

python aws_org_generator.py \
  -o OUTPUT_FILE \
  --role-name ROLE_NAME \
  --external-id EXTERNAL_ID \
  --session-name SESSION_NAME \
  --duration-seconds SECONDS \
  --alias-format FORMAT \
  --exclude ACCOUNT_IDS \
  --include ACCOUNT_IDS \
  --profile AWS_PROFILE \
  --region AWS_REGION \
  --dry-run

Troubleshooting

Error: “No AWS credentials found”

Solution: Configure AWS credentials using one of these methods:
# Method 1: AWS CLI configure
aws configure

# Method 2: Environment variables
export AWS_ACCESS_KEY_ID=your-key-id
export AWS_SECRET_ACCESS_KEY=your-secret-key

# Method 3: Use AWS profile
export AWS_PROFILE=org-management

Error: “Access denied to AWS Organizations API”

Cause: Current credentials don’t have permission to list organization accounts. Solution:
  • Ensure management account credentials are used
  • Verify IAM permissions include organizations:ListAccounts
  • Check IAM policies for Organizations access

Error: “AWS Organizations is not enabled”

Cause: The account is not part of an organization. Solution: This tool requires an AWS Organization. Create one in the AWS Organizations console or use standard bulk provisioning for standalone accounts.

No Accounts Generated After Filters

Cause: All accounts were filtered out by --exclude or --include options. Solution: Review filter options and verify account IDs are correct:
# List all accounts in organization
aws organizations list-accounts --query "Accounts[?Status=='ACTIVE'].[Id,Name]" --output table

Connection Test Failures During Bulk Provisioning

Cause: ProwlerRole may not be deployed correctly or credentials are invalid. Solution:
  • Verify StackSet deployment status in CloudFormation
  • Check role trust policy includes correct external ID
  • Test role assumption manually:
aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/ProwlerRole \
  --role-session-name test \
  --external-id prowler-ext-id-2024

Security Best Practices

Use External ID

Always use an external ID when assuming cross-account roles:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --external-id $(uuidgen | tr '[:upper:]' '[:lower:]')
The external ID must match the one configured in the ProwlerRole trust policy across all accounts.

Exclude Sensitive Accounts

Exclude accounts that shouldn’t be scanned or require special handling:
python aws_org_generator.py \
  -o aws-accounts.yaml \
  --external-id prowler-ext-id \
  --exclude 123456789012,111111111111  # management, break-glass accounts

Review Generated Configuration

Always review the generated YAML before provisioning:
# Check for unexpected accounts
grep "uid:" aws-org-accounts.yaml

# Verify role ARNs
grep "role_arn:" aws-org-accounts.yaml | head -5

# Count accounts
grep "provider: aws" aws-org-accounts.yaml | wc -l

Next Steps

I