+
-### Enter the Management Account Role ARN
+### Enter the Deployment 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** created by the single stack above into the **Management Account Role ARN** field or, when delegated administrator mode is selected, the **Delegated Administrator Account Role ARN** field. If you deployed the management account role beforehand, use the role created in [Step 1](#step-1-create-the-management-account-role).
The ARN follows this format:
```
@@ -312,12 +331,12 @@ arn:aws:iam::
+
### 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:
diff --git a/ui/actions/organizations/organizations.adapter.test.ts b/ui/actions/organizations/organizations.adapter.test.ts
index 07cff60c0c..41e0b8d89f 100644
--- a/ui/actions/organizations/organizations.adapter.test.ts
+++ b/ui/actions/organizations/organizations.adapter.test.ts
@@ -11,6 +11,7 @@ import {
buildOrgTreeData,
getOuIdsForSelectedAccounts,
getSelectableAccountIds,
+ getSelectableAccountIdsForTarget,
} from "./organizations.adapter";
const discoveryFixture: DiscoveryResult = {
@@ -164,6 +165,68 @@ describe("buildAccountLookup", () => {
});
});
+describe("getSelectableAccountIdsForTarget", () => {
+ it("scopes selection to accounts under a target OU, including nested OUs", () => {
+ // ou-parent contains ou-child (holds 111...) and the blocked 222...
+ const scoped = getSelectableAccountIdsForTarget(
+ discoveryFixture,
+ "ou-parent",
+ );
+
+ // Only the selectable descendant is returned; blocked 222... is excluded,
+ // and 333... (under the root, outside the OU) is not included.
+ expect(scoped).toEqual(["111111111111"]);
+ });
+
+ it("scopes selection to a leaf OU", () => {
+ const scoped = getSelectableAccountIdsForTarget(
+ discoveryFixture,
+ "ou-child",
+ );
+
+ expect(scoped).toEqual(["111111111111"]);
+ });
+
+ it("includes the deployment account even when it lives outside the target OU", () => {
+ // Deployment (management) account 333... sits under the root, but gets the
+ // role via DeployLocalRole, so it must be pre-selected alongside the OU.
+ const scoped = getSelectableAccountIdsForTarget(
+ discoveryFixture,
+ "ou-child",
+ "333333333333",
+ );
+
+ expect(scoped).toEqual(["111111111111", "333333333333"]);
+ });
+
+ it("does not include a deployment account that is not selectable", () => {
+ // 222... is blocked, so even as the deployment account it stays unselected.
+ const scoped = getSelectableAccountIdsForTarget(
+ discoveryFixture,
+ "ou-child",
+ "222222222222",
+ );
+
+ expect(scoped).toEqual(["111111111111"]);
+ });
+
+ it("returns every selectable account for a root target (whole organization)", () => {
+ const scoped = getSelectableAccountIdsForTarget(discoveryFixture, "r-root");
+
+ expect(scoped).toEqual(["111111111111", "333333333333"]);
+ });
+
+ it("falls back to all selectable accounts for an empty or unknown target", () => {
+ expect(getSelectableAccountIdsForTarget(discoveryFixture, "")).toEqual([
+ "111111111111",
+ "333333333333",
+ ]);
+ expect(
+ getSelectableAccountIdsForTarget(discoveryFixture, "ou-does-not-exist"),
+ ).toEqual(["111111111111", "333333333333"]);
+ });
+});
+
describe("getOuIdsForSelectedAccounts", () => {
it("collects all ancestor OUs for selected accounts without duplicates", () => {
const ouIds = getOuIdsForSelectedAccounts(discoveryFixture, [
diff --git a/ui/actions/organizations/organizations.adapter.ts b/ui/actions/organizations/organizations.adapter.ts
index e120a1a3dc..2b0c7b5a0b 100644
--- a/ui/actions/organizations/organizations.adapter.ts
+++ b/ui/actions/organizations/organizations.adapter.ts
@@ -109,6 +109,71 @@ export function buildAccountLookup(
return map;
}
+/**
+ * Returns the selectable account IDs that fall under a deployment target
+ * (an OU or root ID), optionally including the deployment account itself.
+ *
+ * The StackSet only rolls the role out to member accounts beneath the chosen
+ * target, and the deployment (management or delegated administrator) account
+ * gets the role via DeployLocalRole even though it usually lives outside that
+ * target. Pre-selecting exactly those accounts keeps the confirmation step in
+ * sync with what was actually deployed.
+ *
+ * Falls back to every selectable account when the target is empty or is not
+ * part of this discovery (e.g. a root ID), preserving the whole-organization
+ * default.
+ */
+export function getSelectableAccountIdsForTarget(
+ result: DiscoveryResult,
+ targetId: string,
+ deploymentAccountId?: string,
+): string[] {
+ const selectableAccountIds = getSelectableAccountIds(result);
+ const normalizedTarget = targetId.trim();
+
+ if (!normalizedTarget) {
+ return selectableAccountIds;
+ }
+
+ const isKnownOu = result.organizational_units.some(
+ (ou) => ou.id === normalizedTarget,
+ );
+
+ // Only a specific OU narrows the selection. A root ID (whole org) or an
+ // unknown target keeps the whole-organization default.
+ if (!isKnownOu) {
+ return selectableAccountIds;
+ }
+
+ // Collect the target OU plus all of its nested descendant OUs.
+ const scopeIds = new Set+ {derivedBucketAccountId + ? `Leave empty to use selected AWS account ${derivedBucketAccountId}, or enter another bucket owner account ID.` + : "Required because the selected provider does not identify the AWS account that owns the bucket."} +
+- 1) Deploy the ProwlerScan role in your{" "} - management account using a CloudFormation - Stack. + 1) Choose the AWS Organizational Unit (or root) + to deploy to. Prowler creates the role in your deployment + account and rolls it out to every member account under this + target.
- +
+ Find this in the AWS Organizations console. Use your{" "}
+ root ID (starts with r-) to deploy
+ to the whole organization, or an OU ID (starts
+ with ou-) to target a specific unit.
+
- 2) Deploy the ProwlerScan role to{" "} - member accounts using a CloudFormation - StackSet. + 2) Create the CloudFormation Stack in your{" "} + {deploymentAccountName}. It deploys the + ProwlerScan role and a service-managed StackSet that rolls the + role out to your member accounts in one step.
-- Open the StackSets console, select{" "} - Service-managed permissions, and paste the - template URL below. Set the ExternalId{" "} - parameter to the value shown above. -
-+ Enter a valid Organizational Unit or Root ID above to enable + deployment. +
+ )}- 3) Paste the management account Role ARN and confirm both - deployments are complete. + 3) Paste the {deploymentAccountName} Role ARN and confirm the + deployment is complete.