From 56bb5e92cc27e80f2a6930dbc7a8f39c937e7e16 Mon Sep 17 00:00:00 2001 From: "Andoni A." <14891798+andoniaf@users.noreply.github.com> Date: Wed, 22 Oct 2025 12:12:36 +0200 Subject: [PATCH] docs: include AWS Orgs bulk importer tutorial --- docs/docs.json | 3 +- .../aws-organizations-bulk-provisioning.mdx | 511 ++++++++++++++++++ .../AWS_ORGANIZATIONS.md | 323 ----------- util/prowler-bulk-provisioning/README.md | 2 +- 4 files changed, 514 insertions(+), 325 deletions(-) create mode 100644 docs/user-guide/tutorials/aws-organizations-bulk-provisioning.mdx delete mode 100644 util/prowler-bulk-provisioning/AWS_ORGANIZATIONS.md diff --git a/docs/docs.json b/docs/docs.json index fb7e91a774..ea64490532 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -114,7 +114,8 @@ "group": "Tutorials", "pages": [ "user-guide/tutorials/prowler-app-sso-entra", - "user-guide/tutorials/bulk-provider-provisioning" + "user-guide/tutorials/bulk-provider-provisioning", + "user-guide/tutorials/aws-organizations-bulk-provisioning" ] } ] diff --git a/docs/user-guide/tutorials/aws-organizations-bulk-provisioning.mdx b/docs/user-guide/tutorials/aws-organizations-bulk-provisioning.mdx new file mode 100644 index 0000000000..302e9aec0a --- /dev/null +++ b/docs/user-guide/tutorials/aws-organizations-bulk-provisioning.mdx @@ -0,0 +1,511 @@ +--- +title: 'AWS Organizations Bulk Provisioning in Prowler' +--- + +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](./bulk-provider-provisioning) tool and is available in the Prowler repository at: [util/prowler-bulk-provisioning](https://github.com/prowler-cloud/prowler/tree/master/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](https://roadmap.prowler.com/p/builk-provisioning-in-the-uiapi-for-aws-organizations-and-alike) + + +{/* TODO: Add screenshot of the tool in action */} + +## 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 token (from Prowler Cloud or self-hosted Prowler App) + * For self-hosted Prowler App, remember to [point to your API base URL](./bulk-provider-provisioning#custom-api-endpoints) + +### 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 Organizations](../providers/aws/organizations#deploying-prowler-iam-roles-across-aws-organizations) + +**Key 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: + +```bash +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 access. Typically this requires: + +* **Management account credentials**, or +* **Delegated administrator account** with `organizations:ListAccounts` permission + +Required IAM permissions: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "organizations:ListAccounts", + "organizations:DescribeOrganization" + ], + "Resource": "*" + } + ] +} +``` + +Configure credentials using one of these methods: + +```bash +# 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 +``` + +### Prowler API Token Setup + +Configure your Prowler API token: + +```bash +export PROWLER_API_TOKEN="your-prowler-api-token" +``` + +To obtain an API token programmatically: + +```bash +export PROWLER_API_TOKEN=$(curl --location 'https://api.prowler.com/api/v1/tokens' \ + --header 'Content-Type: application/vnd.api+json' \ + --header 'Accept: application/vnd.api+json' \ + --data-raw '{ + "data": { + "type": "tokens", + "attributes": { + "email": "your@email.com", + "password": "your-password" + } + } + }' | jq -r .data.attributes.access) +``` + +## Basic Usage + +### Generate Configuration for All Accounts + +To generate a YAML configuration file for all active accounts in the organization: + +```bash +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: + +```bash +head -n 20 aws-accounts.yaml +``` + +**Example output:** + +```yaml +- 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: + +```bash +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: + +```bash +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: + +```bash +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: + +```bash +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`: + +```bash +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: + +```bash +# 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: + +```bash +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. Log into the AWS management account + 2. Navigate to CloudFormation → StackSets + 3. Create a new StackSet using the [Prowler role template](https://github.com/prowler-cloud/prowler/blob/master/permissions/templates/cloudformation/prowler-scan-role.yml) + 4. Deploy to all organizational units + 5. Use a unique external ID (e.g., `prowler-org-2024-abc123`) + + {/* TODO: Add screenshot of CloudFormation StackSets deployment */} + + + + Configure AWS credentials and generate the YAML file: + + ```bash + # 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 + ``` + + + + Verify the generated YAML configuration: + + ```bash + # 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 + ``` + + + + Provision all accounts to Prowler Cloud or Prowler App: + + ```bash + # Set Prowler API credentials + export PROWLER_API_TOKEN="your-prowler-api-token" + + # Run bulk provisioning with connection testing + python prowler_bulk_provisioning.py aws-org-accounts.yaml + ``` + + **With custom options:** + + ```bash + 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 + ``` + + {/* TODO: Add screenshot of successful bulk provisioning output */} + + + +## Command Reference + +### Full Command-Line Options + +```bash +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: + +```bash +# 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: + +```bash +# 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: + +```bash +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: + +```bash +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: + +```bash +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: + +```bash +# 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 +``` + +## Where to go next? + + + + Learn how to bulk provision providers in Prowler. + + + Detailed instructions on how to use Prowler. + + diff --git a/util/prowler-bulk-provisioning/AWS_ORGANIZATIONS.md b/util/prowler-bulk-provisioning/AWS_ORGANIZATIONS.md deleted file mode 100644 index a807a240ca..0000000000 --- a/util/prowler-bulk-provisioning/AWS_ORGANIZATIONS.md +++ /dev/null @@ -1,323 +0,0 @@ -# AWS Organizations Integration Guide - -Automated YAML configuration generator for bulk-provisioning all accounts in an AWS Organization. - -## Overview - -The `aws_org_generator.py` script simplifies provisioning multiple AWS accounts by automatically discovering all accounts in your organization and generating the YAML configuration needed for the bulk provisioning tool. - -## Prerequisites - -### 1. Deploy ProwlerRole Across All Accounts - -Before using this tool, you must deploy the ProwlerRole (or custom role) across all accounts in your organization using CloudFormation StackSets. - -**Follow the official documentation:** -[Deploying Prowler IAM Roles Across AWS Organizations](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/organizations/#deploying-prowler-iam-roles-across-aws-organizations) - -**Key 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 the necessary permissions for Prowler scans - -### 2. AWS Credentials with Organizations Access - -You need AWS credentials with permissions to list organization accounts. Typically, this means: - -- **Using the management account credentials**, or -- **A delegated administrator account** with `organizations:ListAccounts` permission - -Required IAM permissions: -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "organizations:ListAccounts", - "organizations:DescribeOrganization" - ], - "Resource": "*" - } - ] -} -``` - -### 3. Install Dependencies - -```bash -pip install -r requirements-aws-org.txt -``` - -This installs: -- boto3 (AWS SDK) -- PyYAML (YAML parsing) -- requests (HTTP client) - -## Basic Usage - -### Generate Configuration for All Accounts - -```bash -python aws_org_generator.py -o aws-accounts.yaml --external-id prowler-ext-id-2024 -``` - -This will: -1. List all ACTIVE accounts in your organization -2. Generate YAML entries for each account -3. Save to `aws-accounts.yaml` - -### Run Bulk Provisioning - -```bash -python prowler_bulk_provisioning.py aws-accounts.yaml -``` - -## Advanced Usage - -### Using a Specific AWS Profile - -```bash -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 you don't want to scan: - -```bash -python aws_org_generator.py \ - -o aws-accounts.yaml \ - --external-id prowler-ext-id-2024 \ - --exclude 123456789012,210987654321 -``` - -### Including Only Specific Accounts - -Only generate configuration for specific accounts: - -```bash -python aws_org_generator.py \ - -o aws-accounts.yaml \ - --external-id prowler-ext-id-2024 \ - --include 111111111111,222222222222,333333333333 -``` - -### Custom Role Name - -If you deployed a custom role name instead of `ProwlerRole`: - -```bash -python aws_org_generator.py \ - -o aws-accounts.yaml \ - --role-name ProwlerExecutionRole \ - --external-id prowler-ext-id-2024 -``` - -### Custom Alias Format - -Customize how account aliases are generated using template variables: - -```bash -# 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 - -### Dry Run Mode - -Preview the configuration without writing a file: - -```bash -python aws_org_generator.py \ - --external-id prowler-ext-id-2024 \ - --dry-run -``` - -## Complete Workflow Example - -### Step 1: Deploy ProwlerRole Using StackSets - -1. Log into your AWS management account -2. Navigate to 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`) - -### Step 2: Generate YAML Configuration - -```bash -# 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 -``` - -### Step 3: Review Generated Configuration - -```bash -head -n 20 aws-org-accounts.yaml -``` - -### Step 4: Run Bulk Provisioning - -```bash -# Set Prowler API credentials -export PROWLER_API_TOKEN="your-prowler-api-token" - -# Run bulk provisioning (with connection testing) -python prowler_bulk_provisioning.py aws-org-accounts.yaml -``` - -**With custom options:** -```bash -python prowler_bulk_provisioning.py aws-org-accounts.yaml \ - --concurrency 10 \ - --timeout 120 -``` - -## Troubleshooting - -### Error: "No AWS credentials found" - -**Solution:** Configure AWS credentials using one of these methods: - -```bash -# 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 you're using management account credentials -- Verify IAM permissions include `organizations:ListAccounts` - -### 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. - -### No Accounts Generated After Filters - -**Cause:** All accounts were filtered out by `--exclude` or `--include` options. - -**Solution:** Review your filter options and verify account IDs are correct. - -## Security Best Practices - -### Use External ID - -Always use an external ID when assuming cross-account roles: - -```bash -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. - -### Exclude Sensitive Accounts - -Exclude accounts that shouldn't be scanned: - -```bash -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: - -```bash -# 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 -``` - -## Command Reference - -### Full Command-Line Options - -```bash -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 -``` - -### Help Output - -```bash -python aws_org_generator.py --help -``` - -## Support - -For issues or questions: -1. [Prowler Documentation](https://docs.prowler.com) -2. [Prowler GitHub Issues](https://github.com/prowler-cloud/prowler/issues) -3. [Prowler Community Slack](https://prowler.com/slack) diff --git a/util/prowler-bulk-provisioning/README.md b/util/prowler-bulk-provisioning/README.md index e5db60fd5f..478f611328 100644 --- a/util/prowler-bulk-provisioning/README.md +++ b/util/prowler-bulk-provisioning/README.md @@ -73,7 +73,7 @@ This two-step approach follows the Prowler API design where providers and their For organizations with many AWS accounts, use the included `aws_org_generator.py` script to automatically generate configuration for all accounts in your AWS Organization. -**📖 Full Guide:** See [AWS_ORGANIZATIONS.md](AWS_ORGANIZATIONS.md) for complete documentation, examples, and troubleshooting. +**📖 Full Guide:** See [AWS Organizations Bulk Provisioning Tutorial](https://docs.prowler.com/user-guide/tutorials/aws-organizations-bulk-provisioning) for complete documentation, examples, and troubleshooting. ### Prerequisites