From 48385ea142b302f326dc5465eaecafea47a348fc Mon Sep 17 00:00:00 2001
From: Ravina Dhruve <ravina.dhruve@sysdig.com>
Date: Mon, 21 Apr 2025 16:02:06 -0700
Subject: [PATCH] feat(onboarding): Avoid recreating stacksets when new OUs to
 include

---
 README.md                                           |  8 ++++++++
 modules/agentless-scanning/organizational.tf        |  9 ++++++---
 modules/config-posture/organizational.tf            |  4 ++--
 modules/integrations/event-bridge/organizational.tf | 13 ++++++++-----
 modules/onboarding/organizational.tf                |  4 ++--
 modules/vm-workload-scanning/organizational.tf      |  4 ++--
 6 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/README.md b/README.md
index d553cfc..5fbe144 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,14 @@ There are four new parameters to configure organizational deployments on the clo
 
 **WARNING**: module variable `organizational_unit_ids` / `org_units` will be DEPRECATED soon going forward. Please work with Sysdig to migrate your Terraform installs to use `include_ouids` instead to achieve the same deployment outcome.
 
+### Stackset Instances Installation
+
+If new OUs are added in the Include OUIDs list, the existing stackset instances will not get recreated and TF will only create the stackset instances for the newly added OUs.
+
+**Note**: This applies to only OUs added/removed to/from the organizational configuration. If accounts are added/removed from the Exclude Accounts or Include Extra Accounts list, it will end up recreating the stackset instances.
+
+<br/>
+
 ## Best practices
 
 For contributing to existing modules or adding new modules, below are some of the best practices recommended :-
diff --git a/modules/agentless-scanning/organizational.tf b/modules/agentless-scanning/organizational.tf
index 975fe62..f85eefb 100644
--- a/modules/agentless-scanning/organizational.tf
+++ b/modules/agentless-scanning/organizational.tf
@@ -183,12 +183,15 @@ TEMPLATE
 
 # stackset instance to deploy resources for agentless scanning, in all regions of each account in all organization units
 resource "aws_cloudformation_stack_set_instance" "ou_stackset_instance" {
-  for_each   = var.is_organizational ? local.region_set : toset([])
-  region     = each.key
+  for_each = var.is_organizational ? {
+    for pair in setproduct(local.region_set, local.deployment_targets_org_units) :
+    "${pair[0]}-${pair[1]}" => pair
+  } : {}
 
+  region         = each.value[0]
   stack_set_name = aws_cloudformation_stack_set.ou_resources_stackset[0].name
   deployment_targets {
-    organizational_unit_ids = local.deployment_targets_org_units
+    organizational_unit_ids = [each.value[1]]
     accounts                = local.check_old_ouid_param ? null : (local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy)
     account_filter_type     = local.check_old_ouid_param ? null : local.deployment_targets_accounts_filter
   }
diff --git a/modules/config-posture/organizational.tf b/modules/config-posture/organizational.tf
index 1ad1194..a52d1c6 100644
--- a/modules/config-posture/organizational.tf
+++ b/modules/config-posture/organizational.tf
@@ -76,12 +76,12 @@ TEMPLATE
 }
 
 resource "aws_cloudformation_stack_set_instance" "stackset_instance" {
-  count = var.is_organizational ? 1 : 0
+  for_each = var.is_organizational ? toset(local.deployment_targets_org_units) : []
 
   region         = var.region == "" ? null : var.region
   stack_set_name = aws_cloudformation_stack_set.stackset[0].name
   deployment_targets {
-    organizational_unit_ids = local.deployment_targets_org_units
+    organizational_unit_ids = [each.value]
     accounts                = local.check_old_ouid_param ? null : (local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy)
     account_filter_type     = local.check_old_ouid_param ? null : local.deployment_targets_accounts_filter
   }
diff --git a/modules/integrations/event-bridge/organizational.tf b/modules/integrations/event-bridge/organizational.tf
index d3f6715..1c62f42 100644
--- a/modules/integrations/event-bridge/organizational.tf
+++ b/modules/integrations/event-bridge/organizational.tf
@@ -65,12 +65,15 @@ resource "aws_cloudformation_stack_set" "eb_role_stackset" {
 }
 
 resource "aws_cloudformation_stack_set_instance" "eb_rule_api_dest_instance" {
-  for_each = var.is_organizational ? local.region_set : toset([])
-  region   = each.key
+  for_each = var.is_organizational ? {
+    for pair in setproduct(local.region_set, local.deployment_targets_org_units) :
+    "${pair[0]}-${pair[1]}" => pair
+  } : {}
 
+  region         = each.value[0]
   stack_set_name = aws_cloudformation_stack_set.eb_rule_api_dest_stackset[0].name
   deployment_targets {
-    organizational_unit_ids = local.deployment_targets_org_units
+    organizational_unit_ids = [each.value[1]]
     accounts                = local.check_old_ouid_param ? null : (local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy)
     account_filter_type     = local.check_old_ouid_param ? null : local.deployment_targets_accounts_filter
   }
@@ -89,11 +92,11 @@ resource "aws_cloudformation_stack_set_instance" "eb_rule_api_dest_instance" {
 }
 
 resource "aws_cloudformation_stack_set_instance" "eb_role_stackset_instance" {
-  count = var.is_organizational ? 1 : 0
+  for_each = var.is_organizational ? toset(local.deployment_targets_org_units) : []
 
   stack_set_name = aws_cloudformation_stack_set.eb_role_stackset[0].name
   deployment_targets {
-    organizational_unit_ids = local.deployment_targets_org_units
+    organizational_unit_ids = [each.value]
     accounts                = local.check_old_ouid_param ? null : (local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy)
     account_filter_type     = local.check_old_ouid_param ? null : local.deployment_targets_accounts_filter
   }
diff --git a/modules/onboarding/organizational.tf b/modules/onboarding/organizational.tf
index 965c3b0..2c97bb3 100644
--- a/modules/onboarding/organizational.tf
+++ b/modules/onboarding/organizational.tf
@@ -54,12 +54,12 @@ TEMPLATE
 }
 
 resource "aws_cloudformation_stack_set_instance" "stackset_instance" {
-  count = var.is_organizational ? 1 : 0
+  for_each = var.is_organizational ? toset(local.deployment_targets_org_units) : []
 
   region         = var.region == "" ? null : var.region
   stack_set_name = aws_cloudformation_stack_set.stackset[0].name
   deployment_targets {
-    organizational_unit_ids = local.deployment_targets_org_units
+    organizational_unit_ids = [each.value]
     accounts                = local.check_old_ouid_param ? null : (local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy)
     account_filter_type     = local.check_old_ouid_param ? null : local.deployment_targets_accounts_filter
   }
diff --git a/modules/vm-workload-scanning/organizational.tf b/modules/vm-workload-scanning/organizational.tf
index e800951..8df760f 100644
--- a/modules/vm-workload-scanning/organizational.tf
+++ b/modules/vm-workload-scanning/organizational.tf
@@ -120,11 +120,11 @@ resource "aws_cloudformation_stack_set" "scanning_role_stackset" {
 
 # stackset instance to deploy agentless scanning role, in all organization units
 resource "aws_cloudformation_stack_set_instance" "scanning_role_stackset_instance" {
-  count = var.is_organizational ? 1 : 0
+  for_each = var.is_organizational ? toset(local.deployment_targets_org_units) : []
 
   stack_set_name = aws_cloudformation_stack_set.scanning_role_stackset[0].name
   deployment_targets {
-    organizational_unit_ids = local.deployment_targets_org_units
+    organizational_unit_ids = [each.value]
     accounts                = local.check_old_ouid_param ? null : (local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy)
     account_filter_type     = local.check_old_ouid_param ? null : local.deployment_targets_accounts_filter
   }