mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-10 13:34:16 +00:00
feat(ui): one-step AWS Organizations onboarding + S3 bucket account id
This commit is contained in:
1 parent
0d899b3076
commit
89013c561f
13 files changed
+303
-135
No files matched your search
Binary file not shown.
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 330 KiB |
@@ -3,41 +3,37 @@
|
||||
<filter id="shadow" x="-4%" y="-4%" width="108%" height="108%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="3" flood-opacity="0.08"/>
|
||||
</filter>
|
||||
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#9aa0a6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="550" y="40" text-anchor="middle" font-size="22" font-weight="700" fill="#4285F4">Onboarding Flow</text>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<rect x="30" y="70" width="220" height="220" rx="12" fill="#fff" stroke="#4285F4" stroke-width="2.5" stroke-dasharray="8 4" filter="url(#shadow)"/>
|
||||
<rect x="30" y="70" width="220" height="220" rx="12" fill="#fff" stroke="#4285F4" stroke-width="2.5" filter="url(#shadow)"/>
|
||||
<circle cx="140" cy="100" r="22" fill="#4285F4"/>
|
||||
<text x="140" y="107" text-anchor="middle" font-size="16" font-weight="700" fill="#fff">1</text>
|
||||
<text x="140" y="145" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Create Management</text>
|
||||
<text x="140" y="165" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Account Role</text>
|
||||
<rect x="60" y="185" width="160" height="24" rx="12" fill="#E8F0FE"/>
|
||||
<text x="140" y="201" text-anchor="middle" font-size="11" font-weight="600" fill="#4285F4">Quick Create or Manual</text>
|
||||
<text x="140" y="232" text-anchor="middle" font-size="12" fill="#5f6368">Allows Prowler to</text>
|
||||
<text x="140" y="248" text-anchor="middle" font-size="12" fill="#5f6368">discover your org</text>
|
||||
<text x="140" y="264" text-anchor="middle" font-size="12" fill="#5f6368">structure</text>
|
||||
<text x="140" y="150" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Start the Wizard</text>
|
||||
<rect x="75" y="168" width="130" height="24" rx="12" fill="#E8F0FE"/>
|
||||
<text x="140" y="184" text-anchor="middle" font-size="11" font-weight="600" fill="#4285F4">In Prowler Cloud</text>
|
||||
<text x="140" y="216" text-anchor="middle" font-size="12" fill="#5f6368">Enter your Org ID</text>
|
||||
<text x="140" y="232" text-anchor="middle" font-size="12" fill="#5f6368">and OU/root target</text>
|
||||
|
||||
<!-- Arrow 1→2 -->
|
||||
<path d="M260 180 L290 180" stroke="#9aa0a6" stroke-width="2" fill="none" marker-end="url(#arrowhead)"/>
|
||||
<defs>
|
||||
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#9aa0a6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<rect x="300" y="70" width="220" height="220" rx="12" fill="#fff" stroke="#7B61FF" stroke-width="2.5" filter="url(#shadow)"/>
|
||||
<circle cx="410" cy="100" r="22" fill="#7B61FF"/>
|
||||
<text x="410" y="107" text-anchor="middle" font-size="16" font-weight="700" fill="#fff">2</text>
|
||||
<text x="410" y="145" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Deploy StackSet</text>
|
||||
<rect x="340" y="165" width="140" height="24" rx="12" fill="#F3F0FF"/>
|
||||
<text x="410" y="181" text-anchor="middle" font-size="11" font-weight="600" fill="#7B61FF">In AWS Console</text>
|
||||
<text x="410" y="212" text-anchor="middle" font-size="12" fill="#5f6368">Creates ProwlerScan</text>
|
||||
<text x="410" y="228" text-anchor="middle" font-size="12" fill="#5f6368">role in every</text>
|
||||
<text x="410" y="244" text-anchor="middle" font-size="12" fill="#5f6368">member account</text>
|
||||
<text x="410" y="150" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Deploy the Roles</text>
|
||||
<rect x="350" y="168" width="120" height="24" rx="12" fill="#F3F0FF"/>
|
||||
<text x="410" y="184" text-anchor="middle" font-size="11" font-weight="600" fill="#7B61FF">Single CF Stack</text>
|
||||
<text x="410" y="216" text-anchor="middle" font-size="12" fill="#5f6368">Management role +</text>
|
||||
<text x="410" y="232" text-anchor="middle" font-size="12" fill="#5f6368">StackSet to members</text>
|
||||
<text x="410" y="248" text-anchor="middle" font-size="12" fill="#5f6368">in one CF stack</text>
|
||||
|
||||
<!-- Arrow 2→3 -->
|
||||
<path d="M530 180 L560 180" stroke="#9aa0a6" stroke-width="2" fill="none" marker-end="url(#arrowhead)"/>
|
||||
@@ -46,11 +42,11 @@
|
||||
<rect x="570" y="70" width="220" height="220" rx="12" fill="#fff" stroke="#00BFA5" stroke-width="2.5" filter="url(#shadow)"/>
|
||||
<circle cx="680" cy="100" r="22" fill="#00BFA5"/>
|
||||
<text x="680" y="107" text-anchor="middle" font-size="16" font-weight="700" fill="#fff">3</text>
|
||||
<text x="680" y="145" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Run the Wizard</text>
|
||||
<rect x="615" y="165" width="130" height="24" rx="12" fill="#E0F7F4"/>
|
||||
<text x="680" y="181" text-anchor="middle" font-size="11" font-weight="600" fill="#00BFA5">In Prowler Cloud</text>
|
||||
<text x="680" y="212" text-anchor="middle" font-size="12" fill="#5f6368">Discovers accounts,</text>
|
||||
<text x="680" y="228" text-anchor="middle" font-size="12" fill="#5f6368">tests connections</text>
|
||||
<text x="680" y="150" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Discover & Connect</text>
|
||||
<rect x="615" y="168" width="130" height="24" rx="12" fill="#E0F7F4"/>
|
||||
<text x="680" y="184" text-anchor="middle" font-size="11" font-weight="600" fill="#00BFA5">In Prowler Cloud</text>
|
||||
<text x="680" y="216" text-anchor="middle" font-size="12" fill="#5f6368">Discovers accounts,</text>
|
||||
<text x="680" y="232" text-anchor="middle" font-size="12" fill="#5f6368">tests connections</text>
|
||||
|
||||
<!-- Arrow 3→4 -->
|
||||
<path d="M800 180 L830 180" stroke="#9aa0a6" stroke-width="2" fill="none" marker-end="url(#arrowhead)"/>
|
||||
@@ -59,13 +55,13 @@
|
||||
<rect x="840" y="70" width="220" height="220" rx="12" fill="#fff" stroke="#F9AB00" stroke-width="2.5" filter="url(#shadow)"/>
|
||||
<circle cx="950" cy="100" r="22" fill="#F9AB00"/>
|
||||
<text x="950" y="107" text-anchor="middle" font-size="16" font-weight="700" fill="#fff">4</text>
|
||||
<text x="950" y="145" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Launch Scans</text>
|
||||
<rect x="898" y="165" width="104" height="24" rx="12" fill="#FEF7E0"/>
|
||||
<text x="950" y="181" text-anchor="middle" font-size="11" font-weight="600" fill="#F9AB00">Automatic</text>
|
||||
<text x="950" y="212" text-anchor="middle" font-size="12" fill="#5f6368">Scans run on all</text>
|
||||
<text x="950" y="228" text-anchor="middle" font-size="12" fill="#5f6368">connected accounts</text>
|
||||
<text x="950" y="244" text-anchor="middle" font-size="12" fill="#5f6368">on your schedule</text>
|
||||
<text x="950" y="150" text-anchor="middle" font-size="15" font-weight="700" fill="#1a1a2e">Launch Scans</text>
|
||||
<rect x="898" y="168" width="104" height="24" rx="12" fill="#FEF7E0"/>
|
||||
<text x="950" y="184" text-anchor="middle" font-size="11" font-weight="600" fill="#F9AB00">Automatic</text>
|
||||
<text x="950" y="216" text-anchor="middle" font-size="12" fill="#5f6368">Scans run on all</text>
|
||||
<text x="950" y="232" text-anchor="middle" font-size="12" fill="#5f6368">connected accounts</text>
|
||||
<text x="950" y="248" text-anchor="middle" font-size="12" fill="#5f6368">on your schedule</text>
|
||||
|
||||
<!-- Footer -->
|
||||
<text x="550" y="340" text-anchor="middle" font-size="13" fill="#9aa0a6">Steps 1 and 2 are done once in AWS | Steps 3 and 4 are done in Prowler Cloud</text>
|
||||
<text x="550" y="340" text-anchor="middle" font-size="13" fill="#9aa0a6">Step 2 runs once in AWS | Steps 1, 3 and 4 are in Prowler Cloud</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.5 KiB |
@@ -47,7 +47,7 @@
|
||||
|
||||
<!-- Deploy badge -->
|
||||
<rect x="115" y="400" width="270" height="28" rx="14" fill="#FFF3E0" stroke="#F9AB00" stroke-width="1.5"/>
|
||||
<text x="250" y="419" text-anchor="middle" font-size="12" font-weight="700" fill="#E65100">Deploy: Quick Create link or Manual</text>
|
||||
<text x="250" y="419" text-anchor="middle" font-size="12" font-weight="700" fill="#E65100">Deploy: single stack or standalone</text>
|
||||
|
||||
<!-- ===== Prowler Cloud connector ===== -->
|
||||
<rect x="490" y="195" width="120" height="36" rx="8" fill="#F5F5F5" stroke="#E0E0E0" stroke-width="1"/>
|
||||
@@ -86,7 +86,7 @@
|
||||
|
||||
<!-- Deploy badge -->
|
||||
<rect x="735" y="400" width="230" height="28" rx="14" fill="#E8F5E9" stroke="#66BB6A" stroke-width="1.5"/>
|
||||
<text x="850" y="419" text-anchor="middle" font-size="12" font-weight="700" fill="#2E7D32">Deploy: via CloudFormation StackSet</text>
|
||||
<text x="850" y="419" text-anchor="middle" font-size="12" font-weight="700" fill="#2E7D32">Deploy: StackSet (single stack)</text>
|
||||
|
||||
<!-- Footer labels -->
|
||||
<text x="250" y="478" text-anchor="middle" font-size="14" font-weight="700" fill="#4285F4">Prowler discovers</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -73,9 +73,39 @@ The additional fields in CSV header output are as follows:
|
||||
|
||||
When onboarding multiple AWS accounts into Prowler Cloud, it is important to deploy the Prowler Scan IAM Role in each account. The most efficient way to do this across an AWS Organization is by leveraging AWS CloudFormation StackSets, which rolls out infrastructure—like IAM roles—to all accounts centrally from the Management or Delegated Admin account.
|
||||
|
||||
When using Infrastructure as Code (IaC), Terraform is recommended to manage this deployment systematically.
|
||||
### Native CloudFormation StackSet Deployment (Recommended)
|
||||
|
||||
### Recommended Approach
|
||||
The [Prowler Scan IAM Role CloudFormation template](https://github.com/prowler-cloud/prowler/blob/master/permissions/templates/cloudformation/prowler-scan-role.yml) can deploy the role across your entire AWS Organization on its own—no third-party modules required. When launched in the **Management Account** (or a **Delegated Administrator** account) with `DeployStackSet=true` and `EnableOrganizations=true`, it creates a service-managed CloudFormation StackSet that rolls the ProwlerScan role out to every account under the target Organizational Unit (or the organization root), and keeps new accounts covered automatically through auto-deployment.
|
||||
|
||||
To deploy from the CloudFormation console: open **CloudFormation → Create stack → With new resources**, choose **Upload a template file** and select `prowler-scan-role.yml` (or paste its S3 URL), then set the parameters below on the **Specify stack details** step. Leave the **Configure stack options** step at its defaults.
|
||||
|
||||
Deploy a single CloudFormation Stack in the Management Account with the following parameters:
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| `ExternalId` | External ID provided by Prowler Cloud to secure role assumption. | — |
|
||||
| `DeployLocalRole` | Create the ProwlerScan role in this (Management) account. | `true` |
|
||||
| `DeployStackSet` | Create a service-managed StackSet that deploys the role to member accounts. | `false` |
|
||||
| `AWSOrganizationalUnitId` | Target OU (`ou-xxxx-yyyyyyyy`) or organization root (`r-xxxx`) for the StackSet. Required when `DeployStackSet=true`. | `""` |
|
||||
| `DeployFromDelegatedAdmin` | Set to `true` when deploying from a Delegated Administrator account instead of the Management Account (uses `CallAs: DELEGATED_ADMIN`). | `false` |
|
||||
| `EnableOrganizations` | Add AWS Organizations permissions to the Management Account role: read-only account discovery plus the StackSet-management permissions the deployment needs. Set to `true` when deploying in the Management Account. | `false` |
|
||||
| `FailureTolerancePercentage` | Percentage of accounts in which the StackSet operation can fail before CloudFormation stops the operation. | `10` |
|
||||
| `RetainStacksOnAccountRemoval` | Keep the role in an account after it leaves the Organization or OU. | `false` |
|
||||
|
||||
<Warning>
|
||||
On the review step, select **"I acknowledge that AWS CloudFormation might create IAM resources with custom names"** — the template provisions the named `ProwlerScan` IAM role, so the stack requires the `CAPABILITY_NAMED_IAM` capability and fails without this acknowledgment. (The quick-create link handles this for you.)
|
||||
</Warning>
|
||||
|
||||
<Note>
|
||||
The service-managed StackSet does **not** deploy to the Management Account itself. Keeping `DeployLocalRole=true` ensures the role also exists there, so a single stack covers both the Management and member accounts.
|
||||
|
||||
Trusted access for CloudFormation StackSets must be enabled in the Organization (see the note at the top of this page) before `DeployStackSet` will work.
|
||||
|
||||
Deploying for the CLI or a self-hosted Prowler (not Prowler Cloud)? Also set `AccountId` to the account you assume the role from and `IAMPrincipal` to your identity — the defaults target Prowler Cloud. See [Aligning the trust policy with your identity](/user-guide/providers/aws/authentication#trust-policy-align-iamprincipal-with-your-identity).
|
||||
|
||||
</Note>
|
||||
|
||||
### Alternative: Deploy with Terraform
|
||||
|
||||
- **Use StackSets** from the **Management Account** (or a Delegated Admin/Security Account).
|
||||
- **Use Terraform** to orchestrate the deployment.
|
||||
|
||||
@@ -77,6 +77,15 @@ The template requires the following parameters:
|
||||
- **AccountId:** *(Optional)* AWS Account ID that will assume the role (default: Prowler Cloud account)
|
||||
- **IAMPrincipal:** *(Optional)* The IAM principal allowed to assume the role (default: `role/prowler*`)
|
||||
|
||||
<Warning>
|
||||
From the CLI you assume the role with **your own** identity, not from Prowler Cloud. The `AccountId` and `IAMPrincipal` defaults target Prowler Cloud, so set **`AccountId`** to the account you run Prowler from and **`IAMPrincipal`** to your identity (for example `role/<name>` or `user/<name>`). Otherwise `sts:AssumeRole` fails with `AccessDenied`. See [Aligning the trust policy with your identity](/user-guide/providers/aws/authentication#trust-policy-align-iamprincipal-with-your-identity).
|
||||
</Warning>
|
||||
|
||||
<Note>
|
||||
To deploy the role across an entire AWS Organization from a single stack (Management Account role plus a service-managed StackSet for the member accounts), the template also accepts `DeployLocalRole`, `DeployStackSet`, `AWSOrganizationalUnitId`, `DeployFromDelegatedAdmin`, `EnableOrganizations`, `FailureTolerancePercentage`, and `RetainStacksOnAccountRemoval`. See [AWS Organizations in Prowler](/user-guide/providers/aws/organizations#native-cloudformation-stackset-deployment-recommended) for the full parameter reference.
|
||||
|
||||
</Note>
|
||||
|
||||
When running Prowler CLI, include the External ID using the `-I/--external-id` flag:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -272,6 +272,8 @@ python aws_org_generator.py \
|
||||
4. Deploy to all organizational units
|
||||
5. Use a unique external ID (e.g., `prowler-org-2024-abc123`)
|
||||
|
||||
Alternatively, deploy the same template as a **single stack** with `DeployStackSet=true` and `AWSOrganizationalUnitId` set to your root/OU ID — it creates the StackSet for you. See [Native CloudFormation StackSet Deployment](../providers/aws/organizations#native-cloudformation-stackset-deployment-recommended).
|
||||
|
||||
{/* TODO: Add screenshot of CloudFormation StackSets deployment */}
|
||||
</Step>
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ For CLI-based multi-account scanning, see [AWS Organizations in Prowler CLI](/us
|
||||
|
||||
### How It Works
|
||||
|
||||
Before using the AWS Organizations wizard, you need to deploy **two Identity and Access Management (IAM) roles** in your AWS environment. The onboarding follows this sequence:
|
||||
Onboarding deploys the **ProwlerScan Identity and Access Management (IAM) role** in your management account and in every member account. The wizard can deploy both from a **single CloudFormation stack** ([Step 4](#step-4-authenticate-with-your-management-account)), or you can deploy them yourself beforehand using Steps 1–2. The onboarding follows this sequence:
|
||||
|
||||
<Frame>
|
||||
<img src="/images/organizations/onboarding-flow.svg" alt="Onboarding flow: 1. Create Management Account Role (Quick Create or Manual), 2. Deploy StackSet, 3. Run the Wizard, 4. Launch Scans" />
|
||||
<img src="/images/organizations/onboarding-flow.svg" alt="Onboarding flow: 1. Start the Wizard, 2. Deploy the Roles (single CloudFormation stack), 3. Discover and Connect, 4. Launch Scans" />
|
||||
</Frame>
|
||||
|
||||
## Key Concepts
|
||||
@@ -47,8 +47,8 @@ Prowler requires **two separate IAM roles** deployed in different places, each w
|
||||
|
||||
| Role | Where it lives | What it does | How to deploy it |
|
||||
|------|---------------|--------------|------------------|
|
||||
| **ProwlerScan** (management account) | Your management (root) account only | Discovers the Organization structure **and** scans the management account. Has additional Organizations discovery permissions. | Via **Quick Create** link or **manually** in the IAM Console ([Step 1](#step-1-create-the-management-account-role)). Cannot be deployed via StackSet. |
|
||||
| **ProwlerScan** (member accounts) | Every member account | Scans the account for security findings. | Via **CloudFormation StackSet** ([Step 2](#step-2-deploy-the-cloudformation-stackset)). Automated across all accounts. |
|
||||
| **ProwlerScan** (management account) | Your management (root) account only | Discovers the Organization structure **and** scans the management account. Has additional Organizations discovery permissions. | By the wizard's **single stack** ([Step 4](#step-4-authenticate-with-your-management-account)), or on its own via **Quick Create** link or **manually** in the IAM Console ([Step 1](#step-1-create-the-management-account-role)). Cannot be deployed via StackSet. |
|
||||
| **ProwlerScan** (member accounts) | Every member account | Scans the account for security findings. | By the wizard's **single stack** ([Step 4](#step-4-authenticate-with-your-management-account)), or on its own via a **CloudFormation StackSet** ([Step 2](#step-2-deploy-the-cloudformation-stackset)). Automated across all accounts. |
|
||||
|
||||
<Frame caption="Both roles share the same name `ProwlerScan`. The management account role includes additional Organization discovery permissions.">
|
||||
<img src="/images/organizations/two-roles-architecture.svg" alt="Two Roles Architecture: ProwlerScan in management account (Quick Create or Manual, discovery + scanning) and ProwlerScan in member accounts (via StackSet, scanning only)" />
|
||||
@@ -77,7 +77,7 @@ Your AWS environment must have [AWS Organizations](https://docs.aws.amazon.com/o
|
||||
The first role you need to create is the **management account role**. This role allows Prowler to discover your Organization structure — listing accounts, OUs, and hierarchy.
|
||||
|
||||
<Warning>
|
||||
**StackSets do not deploy to the management account.** Organizational CloudFormation StackSets with service-managed permissions only target member accounts — this is an AWS limitation, not a Prowler one. You must create the management account role separately, either via the Quick Create link ([Option A](#option-a-quick-create-link-fastest)) or manually ([Option B](#option-b-create-the-role-manually)).
|
||||
**StackSets do not deploy to the management account.** Organizational CloudFormation StackSets with service-managed permissions only target member accounts — this is an AWS limitation, not a Prowler one. The Prowler wizard works around this by having the **same** stack create the management account role (`DeployLocalRole=true`) alongside the StackSet, so a single deployment covers both. You can also create the management account role on its own via the Quick Create link ([Option A](#option-a-quick-create-link-fastest)) or manually ([Option B](#option-b-create-the-role-manually)).
|
||||
</Warning>
|
||||
|
||||
<Note>
|
||||
@@ -191,7 +191,7 @@ If you just created the role, it may take up to **60 seconds** for AWS to propag
|
||||
|
||||
## Step 2: Deploy the CloudFormation StackSet
|
||||
|
||||
After creating the management account role, the next step is to deploy the **ProwlerScan** role to your member accounts using a CloudFormation StackSet. This is the recommended method for consistent, scalable deployment across your entire organization.
|
||||
This step deploys the **ProwlerScan** role to your member accounts using a CloudFormation StackSet. It is the **manual alternative** to letting the wizard's single stack create the StackSet for you ([Step 4](#step-4-authenticate-with-your-management-account)) — use it if you prefer to create and manage the StackSet yourself.
|
||||
|
||||
The StackSet uses **service-managed permissions**, which means AWS Organizations handles the cross-account deployment automatically — you don't need to create execution roles manually in each account. The StackSet deploys the ProwlerScan IAM role in every target member account, enabling Prowler to assume that role for cross-account scanning.
|
||||
|
||||
@@ -199,9 +199,9 @@ The StackSet uses **service-managed permissions**, which means AWS Organizations
|
||||
**Trusted access required:** CloudFormation StackSets must have trusted access enabled in your management account. Verify this in the AWS Console under **AWS Organizations > Settings > Trusted access for AWS CloudFormation StackSets**.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
**The Quick Create link creates a Stack, not a StackSet.** The link in the Prowler wizard creates a CloudFormation **Stack** that deploys the ProwlerScan role in your management account only ([Step 1](#step-1-create-the-management-account-role)). To deploy the role across **member accounts**, you must create a StackSet manually as described below. AWS does not support Quick Create links for StackSets.
|
||||
</Warning>
|
||||
<Note>
|
||||
**The Prowler wizard now deploys this StackSet for you.** The **Create Stack in Management Account** button ([Step 4](#step-4-authenticate-with-your-management-account)) launches a single CloudFormation Stack that creates the management account role **and** a service-managed StackSet for your member accounts (`DeployStackSet=true`). Use the manual console steps below only if you prefer to create the StackSet yourself.
|
||||
</Note>
|
||||
|
||||
<Tip>
|
||||
**[Open StackSets Console →](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacksets/create)**
|
||||
@@ -243,7 +243,7 @@ Deployment typically takes **2–5 minutes** for medium-sized organizations. Lar
|
||||
|
||||
## Step 3: Start the Organization Wizard
|
||||
|
||||
Now that both roles are deployed — the management account role (Step 1) and the ProwlerScan role in member accounts (Step 2) — you can start the Prowler wizard.
|
||||
Start the Prowler wizard. It walks you through deploying both roles — the management account role and the ProwlerScan role in member accounts — from a single CloudFormation stack ([Step 4](#step-4-authenticate-with-your-management-account)). If you already deployed them beforehand via Steps 1–2, the wizard simply picks up where you left off.
|
||||
|
||||
### Open the Wizard
|
||||
|
||||
@@ -286,23 +286,40 @@ The wizard's **Authentication Details** page guides you through three actions: d
|
||||
|
||||
### External ID
|
||||
|
||||
The wizard displays a **Prowler External ID** at the top — auto-generated and unique to your tenant. Click the copy icon to copy it. You will need this External ID for both the management account Stack and the member accounts StackSet.
|
||||
The wizard displays a **Prowler External ID** at the top — auto-generated and unique to your tenant. Click the copy icon to copy it. The External ID is pre-filled into the deployment link, and the single stack applies it to both the management account role and the member-account StackSet.
|
||||
|
||||
### Deploy the Roles
|
||||
|
||||
The wizard provides two deployment actions:
|
||||
The wizard deploys the management account role and the member-account StackSet in a **single** CloudFormation Stack:
|
||||
|
||||
1. **Create Stack in Management Account** — opens a Quick Create link that deploys the ProwlerScan role with `EnableOrganizations=true` in your management account ([Step 1](#step-1-create-the-management-account-role)). The External ID is pre-filled.
|
||||
1. **Organizational Unit or Root ID** — enter the AWS OU (`ou-xxxx-yyyyyyyy`) or organization root (`r-xxxx`) you want to onboard. Prowler rolls the ProwlerScan role out to every member account under this target. Find it in the [AWS Organizations Console](https://console.aws.amazon.com/organizations/); use the **root ID** (`r-`) to cover the entire organization or an **OU ID** (`ou-`) to target a specific unit.
|
||||
|
||||
2. **Open StackSets Console** — links to the CloudFormation StackSets console where you create a StackSet for member accounts ([Step 2](#step-2-deploy-the-cloudformation-stackset)). Copy the template URL shown in the wizard and paste the External ID manually.
|
||||
2. *(Optional)* Check **"I'm deploying from a delegated administrator account"** if you launch the stack from a delegated administrator account instead of the management account.
|
||||
|
||||
3. **Create Stack in Management Account** — opens a Quick Create link that deploys, in a single stack: the ProwlerScan role in your management account (`DeployLocalRole`, with `EnableOrganizations=true`) **and** a service-managed StackSet (`DeployStackSet`) that rolls the role out to your member accounts. The External ID, OU/Root ID, and deployment options are pre-filled.
|
||||
|
||||
<Tip>
|
||||
**Finding your Organizational Unit or Root ID.** In the [AWS Organizations Console](https://console.aws.amazon.com/organizations/) the root (`r-…`) and OU (`ou-…`) IDs appear in the account tree, or run these from your management account:
|
||||
|
||||
```bash
|
||||
# Root ID — deploys the role to the entire organization
|
||||
aws organizations list-roots --query 'Roots[0].Id' --output text
|
||||
|
||||
# OU IDs under the root — to target a specific unit instead
|
||||
aws organizations list-organizational-units-for-parent --parent-id r-xxxx \
|
||||
--query 'OrganizationalUnits[].{Name:Name,Id:Id}' --output table
|
||||
```
|
||||
|
||||
If you deploy the CloudFormation template manually (instead of via the wizard link), set **`DeployStackSet=true`**, **`DeployLocalRole=true`**, and **`EnableOrganizations=true`**, then put the root/OU ID above into **`AWSOrganizationalUnitId`** (required whenever `DeployStackSet=true`). Leave **`DeployFromDelegatedAdmin=false`** unless you launch the stack from a delegated administrator account.
|
||||
</Tip>
|
||||
|
||||
<Frame>
|
||||
<img src="/images/organizations/authentication-details.png" alt="Authentication Details form showing External ID, two deployment buttons (Create Stack in Management Account and Open StackSets Console), Management Account Role ARN field, and deployment confirmation checkbox" />
|
||||
<img src="/images/organizations/authentication-details.png" alt="Authentication Details form showing External ID, Organizational Unit or Root ID field, delegated administrator checkbox, the Create Stack in Management Account button, Management Account Role ARN field, and deployment confirmation checkbox" />
|
||||
</Frame>
|
||||
|
||||
### Enter the Management Account Role ARN
|
||||
|
||||
Paste the **Role ARN** of the management account role you created in [Step 1](#step-1-create-the-management-account-role) into the **Management Account Role ARN** field.
|
||||
Paste the **Role ARN** of the management account role — created by the single stack above, or beforehand in [Step 1](#step-1-create-the-management-account-role) — into the **Management Account Role ARN** field.
|
||||
|
||||
The ARN follows this format:
|
||||
```
|
||||
@@ -317,7 +334,7 @@ For example: `arn:aws:iam::123456789012:role/ProwlerScan`
|
||||
|
||||
### Confirm and Discover
|
||||
|
||||
1. Check the box: **"The Stack and StackSet have been successfully deployed in AWS"**.
|
||||
1. Check the box: **"The Stack has been successfully deployed in AWS"**.
|
||||
2. Click **Authenticate**.
|
||||
|
||||
Here's what happens behind the scenes:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
AWS Organizations onboarding now deploys the management account role and the member-account StackSet from a single CloudFormation stack, replacing the manual StackSet console step
|
||||
@@ -0,0 +1 @@
|
||||
The AWS S3 integration CloudFormation quick-create link now sets the bucket owner account ID, preventing a stack validation error when S3 integration is enabled
|
||||
@@ -75,6 +75,7 @@ export const S3IntegrationForm = ({
|
||||
defaultValues: {
|
||||
integration_type: "amazon_s3" as const,
|
||||
bucket_name: integration?.attributes.configuration.bucket_name || "",
|
||||
bucket_account_id: "",
|
||||
output_directory:
|
||||
integration?.attributes.configuration.output_directory || "output",
|
||||
providers:
|
||||
@@ -95,6 +96,26 @@ export const S3IntegrationForm = ({
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
// Derives the AWS Account ID that owns the S3 bucket from the selected
|
||||
// provider(s). For AWS providers the uid is the 12-digit account id. This is
|
||||
// the common case (bucket lives in a scanned account); cross-account buckets
|
||||
// can still be overridden via the "Bucket owner account ID" field.
|
||||
const deriveBucketAccountId = (): string => {
|
||||
const selectedIds = form.getValues("providers") || [];
|
||||
for (const id of selectedIds) {
|
||||
const provider = providers.find((p) => p.id === id);
|
||||
const uid = provider?.attributes.uid;
|
||||
if (
|
||||
provider?.attributes.provider === "aws" &&
|
||||
uid &&
|
||||
/^\d{12}$/.test(uid)
|
||||
) {
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const handleNext = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -103,10 +124,17 @@ export const S3IntegrationForm = ({
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate current step fields for creation flow
|
||||
// Validate current step fields for creation flow. bucket_account_id is
|
||||
// validated here, while its input is visible, so a malformed value surfaces
|
||||
// its error instead of silently blocking the step 1 submit.
|
||||
const stepFields =
|
||||
currentStep === 0
|
||||
? (["bucket_name", "output_directory", "providers"] as const)
|
||||
? ([
|
||||
"bucket_name",
|
||||
"output_directory",
|
||||
"providers",
|
||||
"bucket_account_id",
|
||||
] as const)
|
||||
: // Step 1: No required fields since role_arn and external_id are optional
|
||||
[];
|
||||
|
||||
@@ -259,12 +287,15 @@ export const S3IntegrationForm = ({
|
||||
// If editing credentials, show only credentials form
|
||||
if (isEditingCredentials || currentStep === 1) {
|
||||
const bucketName = form.getValues("bucket_name") || "";
|
||||
const bucketAccountId =
|
||||
form.getValues("bucket_account_id") || deriveBucketAccountId();
|
||||
const externalId =
|
||||
form.getValues("external_id") || session?.tenantId || "";
|
||||
const templateLinks = getAWSCredentialsTemplateLinks(
|
||||
externalId,
|
||||
bucketName,
|
||||
"amazon_s3",
|
||||
bucketAccountId,
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -346,6 +377,24 @@ export const S3IntegrationForm = ({
|
||||
variant="bordered"
|
||||
isRequired
|
||||
/>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="bucket_account_id"
|
||||
type="text"
|
||||
label="Bucket owner account ID (optional)"
|
||||
labelPlacement="inside"
|
||||
placeholder="Defaults to the selected account"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
/>
|
||||
<p className="text-text-neutral-tertiary text-xs">
|
||||
AWS account ID that owns the bucket. Leave empty to use the
|
||||
selected account, or set it if the bucket lives in a different
|
||||
account.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -24,11 +24,7 @@ import { Button } from "@/components/shadcn/button/button";
|
||||
import { Checkbox } from "@/components/shadcn/checkbox/checkbox";
|
||||
import { Form } from "@/components/shadcn/form";
|
||||
import { Spinner } from "@/components/shadcn/spinner/spinner";
|
||||
import {
|
||||
getAWSCredentialsTemplateLinks,
|
||||
PROWLER_CF_TEMPLATE_URL,
|
||||
STACKSET_CONSOLE_URL,
|
||||
} from "@/lib";
|
||||
import { getAWSOrgDeploymentQuickLink } from "@/lib";
|
||||
import { useOrgSetupStore } from "@/store/organizations/store";
|
||||
import { ORG_SETUP_PHASE, OrgSetupPhase } from "@/types/organizations";
|
||||
|
||||
@@ -52,8 +48,14 @@ const orgSetupSchema = z.object({
|
||||
/^arn:aws:iam::\d{12}:role\//,
|
||||
"Must be a valid IAM Role ARN (e.g., arn:aws:iam::123456789012:role/ProwlerScan)",
|
||||
),
|
||||
// OU or root id the StackSet deploys to. UI-only: used to build the
|
||||
// CloudFormation quick-create link, not sent to the backend. Its format is
|
||||
// validated inline (isOrgUnitIdValid) to gate the deployment button, so a
|
||||
// malformed value never blocks the Authenticate submit.
|
||||
organizationalUnitId: z.string().trim().optional(),
|
||||
deployFromDelegatedAdmin: z.boolean().optional(),
|
||||
stackSetDeployed: z.boolean().refine((value) => value, {
|
||||
message: "You must confirm the StackSet deployment before continuing.",
|
||||
message: "You must confirm the deployment before continuing.",
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -91,9 +93,7 @@ export function OrgSetupForm({
|
||||
const { toast } = useToast();
|
||||
const COPY_RESET_TIMEOUT = 1500;
|
||||
const [isExternalIdCopied, setIsExternalIdCopied] = useState(false);
|
||||
const [isTemplateUrlCopied, setIsTemplateUrlCopied] = useState(false);
|
||||
const externalIdCopyTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
||||
const templateUrlCopyTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
||||
|
||||
// Copies text and flips the copied flag back after the timeout, without effects
|
||||
const copyWithFeedback = (
|
||||
@@ -110,8 +110,6 @@ export function OrgSetupForm({
|
||||
|
||||
const copyExternalId = (text: string) =>
|
||||
copyWithFeedback(text, setIsExternalIdCopied, externalIdCopyTimer);
|
||||
const copyTemplateUrl = (text: string) =>
|
||||
copyWithFeedback(text, setIsTemplateUrlCopied, templateUrlCopyTimer);
|
||||
const [setupPhase, setSetupPhase] = useState<OrgSetupPhase>(initialPhase);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const formId = "org-wizard-setup-form";
|
||||
@@ -126,6 +124,8 @@ export function OrgSetupForm({
|
||||
organizationName: initialValues?.organizationName ?? "",
|
||||
awsOrgId: initialValues?.awsOrgId ?? "",
|
||||
roleArn: "",
|
||||
organizationalUnitId: "",
|
||||
deployFromDelegatedAdmin: false,
|
||||
stackSetDeployed: false,
|
||||
},
|
||||
});
|
||||
@@ -139,10 +139,21 @@ export function OrgSetupForm({
|
||||
|
||||
const awsOrgId = watch("awsOrgId") || "";
|
||||
const isOrgIdValid = /^o-[a-z0-9]{10,32}$/.test(awsOrgId.trim());
|
||||
const templateLinks = stackSetExternalId
|
||||
? getAWSCredentialsTemplateLinks(stackSetExternalId)
|
||||
: null;
|
||||
const orgQuickLink = templateLinks?.cloudformationOrgQuickLink;
|
||||
|
||||
const organizationalUnitId = watch("organizationalUnitId") || "";
|
||||
const deployFromDelegatedAdmin = watch("deployFromDelegatedAdmin") || false;
|
||||
const isOrgUnitIdValid =
|
||||
/^(ou-[a-z0-9]{4,32}-[a-z0-9]{8,32}|r-[a-z0-9]{4,32})$/.test(
|
||||
organizationalUnitId.trim(),
|
||||
);
|
||||
const orgQuickLink =
|
||||
stackSetExternalId && isOrgUnitIdValid
|
||||
? getAWSOrgDeploymentQuickLink({
|
||||
externalId: stackSetExternalId,
|
||||
organizationalUnitId: organizationalUnitId.trim(),
|
||||
deployFromDelegatedAdmin,
|
||||
})
|
||||
: null;
|
||||
|
||||
const { apiError, setApiError, submitOrganizationSetup } =
|
||||
useOrgSetupSubmission({
|
||||
@@ -381,12 +392,66 @@ export function OrgSetupForm({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Step 1: Management account - CloudFormation Stack */}
|
||||
{/* Step 1: Choose the deployment target */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-text-neutral-primary text-sm leading-7 font-normal">
|
||||
1) Deploy the ProwlerScan role in your{" "}
|
||||
<strong>management account</strong> using a CloudFormation
|
||||
Stack.
|
||||
1) Choose the AWS <strong>Organizational Unit</strong> (or root)
|
||||
to deploy to. Prowler creates the role in your management
|
||||
account and rolls it out to every member account under this
|
||||
target.
|
||||
</p>
|
||||
<WizardInputField
|
||||
control={control}
|
||||
name="organizationalUnitId"
|
||||
label="Organizational Unit or Root ID"
|
||||
labelPlacement="outside"
|
||||
placeholder="e.g. r-abcd or ou-abcd-1a2b3c4d"
|
||||
isRequired={false}
|
||||
normalizeValue={(value) => value.toLowerCase()}
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
spellCheck={false}
|
||||
/>
|
||||
<p className="text-text-neutral-tertiary text-xs leading-5">
|
||||
Find this in the AWS Organizations console. Use your{" "}
|
||||
<strong>root ID</strong> (starts with <code>r-</code>) to deploy
|
||||
to the whole organization, or an <strong>OU ID</strong> (starts
|
||||
with <code>ou-</code>) to target a specific unit.
|
||||
</p>
|
||||
<div className="flex items-start gap-4">
|
||||
<Controller
|
||||
name="deployFromDelegatedAdmin"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<Checkbox
|
||||
id="deployFromDelegatedAdmin"
|
||||
className="mt-0.5"
|
||||
checked={field.value}
|
||||
onCheckedChange={(checked) =>
|
||||
field.onChange(Boolean(checked))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="deployFromDelegatedAdmin"
|
||||
className="text-text-neutral-tertiary text-xs leading-5 font-normal"
|
||||
>
|
||||
I'm deploying from a delegated administrator
|
||||
account (not the Organization management account)
|
||||
</label>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Step 2: Single CloudFormation Stack (role + StackSet) */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-text-neutral-primary text-sm leading-7 font-normal">
|
||||
2) Create the CloudFormation Stack in your{" "}
|
||||
<strong>management account</strong>. It deploys the ProwlerScan
|
||||
role and a service-managed StackSet that rolls the role out to
|
||||
your member accounts in one step.
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -404,61 +469,19 @@ export function OrgSetupForm({
|
||||
<span>Create Stack in Management Account</span>
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Step 2: Member accounts - CloudFormation StackSet */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-text-neutral-primary text-sm leading-7 font-normal">
|
||||
2) Deploy the ProwlerScan role to{" "}
|
||||
<strong>member accounts</strong> using a CloudFormation
|
||||
StackSet.
|
||||
</p>
|
||||
<p className="text-text-neutral-tertiary text-xs leading-5">
|
||||
Open the StackSets console, select{" "}
|
||||
<strong>Service-managed permissions</strong>, and paste the
|
||||
template URL below. Set the <strong>ExternalId</strong>{" "}
|
||||
parameter to the value shown above.
|
||||
</p>
|
||||
<div className="bg-bg-neutral-tertiary border-border-input-primary flex items-center gap-3 rounded-lg border px-4 py-2.5">
|
||||
<span className="text-text-neutral-primary min-w-0 flex-1 truncate font-mono text-xs">
|
||||
{PROWLER_CF_TEMPLATE_URL}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyTemplateUrl(PROWLER_CF_TEMPLATE_URL)}
|
||||
className="text-text-neutral-secondary hover:text-text-neutral-primary shrink-0 transition-colors"
|
||||
aria-label="Copy template URL"
|
||||
>
|
||||
{isTemplateUrlCopied ? (
|
||||
<Check className="size-4" />
|
||||
) : (
|
||||
<Copy className="size-4" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="border-border-input-primary bg-bg-input-primary text-button-tertiary hover:bg-bg-input-primary active:bg-bg-input-primary h-12 w-full justify-start"
|
||||
disabled={!isExternalIdCopied}
|
||||
asChild
|
||||
>
|
||||
<a
|
||||
href={STACKSET_CONSOLE_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<ExternalLink className="size-5" />
|
||||
<span>Open StackSets Console</span>
|
||||
</a>
|
||||
</Button>
|
||||
{!isOrgUnitIdValid && (
|
||||
<p className="text-text-neutral-tertiary text-xs leading-5">
|
||||
Enter a valid Organizational Unit or Root ID above to enable
|
||||
deployment.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Step 3: Role ARN + confirm */}
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-text-neutral-primary text-sm leading-7 font-normal">
|
||||
3) Paste the management account Role ARN and confirm both
|
||||
deployments are complete.
|
||||
3) Paste the management account Role ARN and confirm the
|
||||
deployment is complete.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -495,8 +518,7 @@ export function OrgSetupForm({
|
||||
htmlFor="stackSetDeployed"
|
||||
className="text-text-neutral-tertiary text-xs leading-5 font-normal"
|
||||
>
|
||||
The Stack and StackSet have been successfully deployed in
|
||||
AWS
|
||||
The Stack has been successfully deployed in AWS
|
||||
<span className="text-text-error-primary">*</span>
|
||||
</label>
|
||||
</>
|
||||
|
||||
+44
-11
@@ -18,8 +18,8 @@ export const DOCS_URLS = {
|
||||
} as const;
|
||||
|
||||
// CloudFormation template URL for the ProwlerScan role.
|
||||
// Also used (URL-encoded) as the templateURL param in cloudformationQuickLink
|
||||
// and cloudformationOrgQuickLink below — keep both in sync.
|
||||
// Also used (URL-encoded) as the templateURL param in the quick-create links
|
||||
// built by getAWSCredentialsTemplateLinks and getAWSOrgDeploymentQuickLink below.
|
||||
export const PROWLER_CF_TEMPLATE_URL =
|
||||
"https://prowler-cloud-public.s3.eu-west-1.amazonaws.com/permissions/templates/aws/cloudformation/prowler-scan-role.yml";
|
||||
|
||||
@@ -32,6 +32,11 @@ export const BILLING_URL = "https://cloud.prowler.com/billing";
|
||||
export const STACKSET_CONSOLE_URL =
|
||||
"https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacksets/create";
|
||||
|
||||
// Base URL for the CloudFormation "quick create stack" console flow.
|
||||
// Hardcoded to us-east-1, same rationale as STACKSET_CONSOLE_URL above.
|
||||
const CF_QUICKCREATE_BASE_URL =
|
||||
"https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate";
|
||||
|
||||
export const getProviderHelpText = (provider: string) => {
|
||||
switch (provider) {
|
||||
case "aws":
|
||||
@@ -126,11 +131,11 @@ export const getAWSCredentialsTemplateLinks = (
|
||||
externalId: string,
|
||||
bucketName?: string,
|
||||
integrationType?: IntegrationType,
|
||||
bucketAccountId?: string,
|
||||
): {
|
||||
cloudformation: string;
|
||||
terraform: string;
|
||||
cloudformationQuickLink: string;
|
||||
cloudformationOrgQuickLink: string;
|
||||
} => {
|
||||
let links = {};
|
||||
|
||||
@@ -153,10 +158,14 @@ export const getAWSCredentialsTemplateLinks = (
|
||||
}
|
||||
|
||||
const encodedTemplateUrl = encodeURIComponent(PROWLER_CF_TEMPLATE_URL);
|
||||
const cfBaseUrl =
|
||||
"https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate";
|
||||
// The template requires S3IntegrationBucketAccountId (owner account of the
|
||||
// bucket) whenever EnableS3Integration is true, so include it alongside the
|
||||
// bucket name to avoid a stack validation error on the quick-create flow.
|
||||
const s3Params = bucketName
|
||||
? `¶m_EnableS3Integration=true¶m_S3IntegrationBucketName=${bucketName}`
|
||||
? `¶m_EnableS3Integration=true¶m_S3IntegrationBucketName=${bucketName}` +
|
||||
(bucketAccountId
|
||||
? `¶m_S3IntegrationBucketAccountId=${bucketAccountId}`
|
||||
: "")
|
||||
: "";
|
||||
|
||||
return {
|
||||
@@ -165,11 +174,35 @@ export const getAWSCredentialsTemplateLinks = (
|
||||
terraform: string;
|
||||
}),
|
||||
cloudformationQuickLink:
|
||||
`${cfBaseUrl}?templateURL=${encodedTemplateUrl}` +
|
||||
`${CF_QUICKCREATE_BASE_URL}?templateURL=${encodedTemplateUrl}` +
|
||||
`&stackName=Prowler¶m_ExternalId=${externalId}${s3Params}`,
|
||||
cloudformationOrgQuickLink:
|
||||
`${cfBaseUrl}?templateURL=${encodedTemplateUrl}` +
|
||||
`&stackName=Prowler¶m_ExternalId=${externalId}` +
|
||||
`¶m_EnableOrganizations=true${s3Params}`,
|
||||
};
|
||||
};
|
||||
|
||||
// Builds the CloudFormation quick-create link that onboards an entire AWS
|
||||
// Organization in a single stack: it creates the ProwlerScan role in the
|
||||
// management account (DeployLocalRole) and a service-managed StackSet that
|
||||
// rolls the role out to the member accounts under the given OU/root
|
||||
// (DeployStackSet). Set deployFromDelegatedAdmin when launching from a
|
||||
// delegated administrator account instead of the management account.
|
||||
export const getAWSOrgDeploymentQuickLink = ({
|
||||
externalId,
|
||||
organizationalUnitId,
|
||||
deployFromDelegatedAdmin = false,
|
||||
}: {
|
||||
externalId: string;
|
||||
organizationalUnitId: string;
|
||||
deployFromDelegatedAdmin?: boolean;
|
||||
}): string => {
|
||||
const encodedTemplateUrl = encodeURIComponent(PROWLER_CF_TEMPLATE_URL);
|
||||
|
||||
return (
|
||||
`${CF_QUICKCREATE_BASE_URL}?templateURL=${encodedTemplateUrl}` +
|
||||
`&stackName=Prowler¶m_ExternalId=${externalId}` +
|
||||
"¶m_EnableOrganizations=true" +
|
||||
"¶m_DeployLocalRole=true" +
|
||||
"¶m_DeployStackSet=true" +
|
||||
`¶m_AWSOrganizationalUnitId=${organizationalUnitId}` +
|
||||
(deployFromDelegatedAdmin ? "¶m_DeployFromDelegatedAdmin=true" : "")
|
||||
);
|
||||
};
|
||||
@@ -202,6 +202,14 @@ const baseS3IntegrationSchema = z.object({
|
||||
integration_type: z.literal("amazon_s3"),
|
||||
bucket_name: z.string().min(1, "Bucket name is required"),
|
||||
output_directory: z.string().min(1, "Output directory is required"),
|
||||
// UI-only field used to prefill the S3IntegrationBucketAccountId parameter of
|
||||
// the CloudFormation quick-create link. Not sent to the backend.
|
||||
bucket_account_id: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((value) => !value || /^\d{12}$/.test(value), {
|
||||
message: "Must be a valid 12-digit AWS Account ID",
|
||||
}),
|
||||
providers: z.array(z.string()).optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
...awsCredentialFields,
|
||||
|
||||
Reference in new issue
Block a user