Skip to content

Commit 0432c57

Browse files
SSPROD-59007 - include/exclude TF provisioning support (#76)
* SSPROD-59005 - feat: include/exclude and automatic onboarding vars * SSPROD-59005 - feat: include/exclude and automatic onboarding vars * SSPROD-59007 - include/exclude TF provisioning support * Add unique random ids to role name key * SSPROD-59007 - include/exclude TF provisioning support * SSPROD-59007 - include/exclude TF provisioning support * SSPROD-59007 - include/exclude TF provisioning support * SSPROD-59007 - include/exclude TF provisioning support * SSPROD-59007 - include/exclude TF provisioning support --------- Co-authored-by: Ravina Dhruve <ravina.dhruve@sysdig.com>
1 parent 419f35b commit 0432c57

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1148
-165
lines changed

modules/agentless-scanning/README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,16 @@ No modules.
5151

5252
## Inputs
5353

54-
| Name | Description | Type | Default | Required |
55-
|------|-------------|------|---------|:--------:|
56-
| <a name="input_is_organizational"></a> [is\_organizational](#input\_is\_organizational) | (Optional) Set this field to 'true' to deploy secure-for-cloud to an Azure Tenant. | `bool` | `false` | no |
57-
| <a name="input_management_group_ids"></a> [management\_group\_ids](#input\_management\_group\_ids) | (Optional) List of Azure Management Group IDs. secure-for-cloud will be deployed to all the subscriptions under these management groups. | `set(string)` | `[]` | no |
58-
| <a name="input_subscription_id"></a> [subscription\_id](#input\_subscription\_id) | Subscription ID in which to create a trust relationship | `string` | n/a | yes |
59-
| <a name="input_sysdig_secure_account_id"></a> [sysdig\_secure\_account\_id](#input\_sysdig\_secure\_account\_id) | ID of the Sysdig Cloud Account to enable Agentless Scanning for (incase of organization, ID of the Sysdig management account) | `string` | n/a | yes |
54+
| Name | Description | Type | Default | Required |
55+
|------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|---------|:--------:|
56+
| <a name="input_is_organizational"></a> [is\_organizational](#input\_is\_organizational) | (Optional) Set this field to 'true' to deploy secure-for-cloud to an Azure Tenant. | `bool` | `false` | no |
57+
| <a name="input_management_group_ids"></a> [suffix](#input\_management\_group\_ids) | TO BE DEPRECATED on 30th November, 2025: Please work with Sysdig to migrate to using `include_management_groups` instead.<br> List of Azure Management Group IDs. secure-for-cloud will be deployed to all the subscriptions under these management groups. If not provided, set to empty by default | `set(string)` | `[]` | no |
58+
| <a name="input_subscription_id"></a> [subscription\_id](#input\_subscription\_id) | Subscription ID in which to create a trust relationship | `string` | n/a | yes |
59+
| <a name="input_sysdig_secure_account_id"></a> [sysdig\_secure\_account\_id](#input\_sysdig\_secure\_account\_id) | ID of the Sysdig Cloud Account to enable Agentless Scanning for (incase of organization, ID of the Sysdig management account) | `string` | n/a | yes |
60+
| <a name="input_include_management_groups"></a> [suffix](#input\_include\_management_groups) | management_groups to include for organization in the format '<management_group_idt>' i.e: management_group_id_1 | `set(string)` | `[]` | no |
61+
| <a name="input_exclude_management_groups"></a> [suffix](#input\_exclude\_management_groups) | management_groups to exclude for organization in the format '<management_group_idt>' i.e: management_group_id_1 | `set(string)` | `[]` | no |
62+
| <a name="input_include_subscriptions"></a> [suffix](#input\_include\_subscriptions) | subscriptions to include for organization. i.e: 12345678-1234-1234-1234-123456789abc | `set(string)` | `[]` | no |
63+
| <a name="input_exclude_subscriptions"></a> [suffix](#input\_exclude\_subscriptions) | subscriptions to exclude for organization. i.e: 12345678-1234-1234-1234-123456789abc | `set(string)` | `[]` | no |
6064

6165
## Outputs
6266

modules/agentless-scanning/locals.tf

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
locals {
2+
# check if both old and new include/exclude org parameters are used, we fail early
3+
both_org_configuration_params = var.is_organizational && length(var.management_group_ids) > 0 && (
4+
length(var.include_management_groups) > 0 ||
5+
length(var.exclude_management_groups) > 0 ||
6+
length(var.include_subscriptions) > 0 ||
7+
length(var.exclude_subscriptions) > 0
8+
)
9+
10+
# check if old management_group_ids parameter is provided, for backwards compatibility we will always give preference to it
11+
check_old_management_group_ids_param = var.is_organizational && length(var.management_group_ids) > 0
12+
13+
# legacy mode: use management_group_ids if provided
14+
selected_management_group = var.is_organizational && local.check_old_management_group_ids_param ? (length(data.azurerm_management_group.management_groups) > 0 ? values(data.azurerm_management_group.management_groups) : [data.azurerm_management_group.root_management_group[0]]) : []
15+
16+
# legacy mode: get all subscriptions from selected management groups
17+
legacy_all_mg_subscription_ids = flatten([
18+
for mg in local.selected_management_group : mg.all_subscription_ids
19+
])
20+
21+
# unified recursive mode: get subscriptions from granular-subscriptions modules when include_management_groups or exclude_management_groups is provided
22+
discovered_subscription_ids = var.is_organizational && !local.check_old_management_group_ids_param && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? (
23+
flatten([
24+
module.level0[0].subscriptions,
25+
module.level1[0].subscriptions,
26+
module.level2[0].subscriptions,
27+
module.level3[0].subscriptions,
28+
module.level4[0].subscriptions,
29+
module.level5[0].subscriptions,
30+
module.level6[0].subscriptions
31+
])
32+
) : []
33+
34+
# include specific subscriptions that are not already discovered
35+
additional_subscription_ids = var.is_organizational && !local.check_old_management_group_ids_param && length(var.include_subscriptions) > 0 ? (
36+
[for s in var.include_subscriptions : s if !(contains(local.discovered_subscription_ids, s))]
37+
) : []
38+
39+
# combine discovered and additional subscriptions
40+
new_all_subscription_ids = concat(local.discovered_subscription_ids, local.additional_subscription_ids)
41+
42+
# default mode: use root management group subscriptions when no include/exclude filters are provided
43+
default_all_mg_subscription_ids = var.is_organizational && !local.check_old_management_group_ids_param && length(var.include_management_groups) == 0 && length(var.exclude_management_groups) == 0 ? (
44+
length(var.exclude_subscriptions) > 0 ? (
45+
[for s in data.azurerm_management_group.root_management_group[0].all_subscription_ids : s if !(contains(var.exclude_subscriptions, s))]
46+
) : (
47+
data.azurerm_management_group.root_management_group[0].all_subscription_ids
48+
)
49+
) : []
50+
51+
# combine all subscription ids based on mode
52+
all_mg_subscription_ids = concat(
53+
local.legacy_all_mg_subscription_ids,
54+
local.new_all_subscription_ids,
55+
local.default_all_mg_subscription_ids
56+
)
57+
}
58+
59+
check "validate_org_configuration_params" {
60+
assert {
61+
condition = length(var.management_group_ids) == 0 # if this condition is false we throw warning
62+
error_message = <<-EOT
63+
WARNING: 'management_group_ids' TO BE DEPRECATED on 30th November, 2025: Please work with Sysdig to migrate your Terraform installs to use 'include_management_groups' instead.
64+
EOT
65+
}
66+
67+
assert {
68+
condition = !local.both_org_configuration_params # if this condition is false we throw error
69+
error_message = <<-EOT
70+
ERROR: If both management_group_ids and include_management_groups/exclude_management_groups/include_subscriptions/exclude_subscriptions variables are populated,
71+
ONLY management_group_ids will be considered. Please use only one of the two methods.
72+
Note: management_group_ids is going to be DEPRECATED on 30th November, 2025. Please work with Sysdig to migrate your Terraform installs.
73+
EOT
74+
}
75+
}

modules/agentless-scanning/main.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ resource "azurerm_lighthouse_assignment" "lighthouse_assignment" {
3434
# explicit dependency using depends_on
3535
#-----------------------------------------------------------------------------------------------------------------
3636
resource "sysdig_secure_cloud_auth_account_component" "azure_service_principal" {
37-
account_id = var.sysdig_secure_account_id
38-
type = "COMPONENT_SERVICE_PRINCIPAL"
39-
instance = "secure-scanning"
37+
account_id = var.sysdig_secure_account_id
38+
type = "COMPONENT_SERVICE_PRINCIPAL"
39+
instance = "secure-scanning"
4040
service_principal_metadata = jsonencode({
4141
azure = {
4242
active_directory_service_principal = {

modules/agentless-scanning/organizational.tf

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#---------------------------------------------------------------------------------------------
44
# If no management group is present, then the root management group is used to onboard all the subscriptions
55
data "azurerm_management_group" "root_management_group" {
6-
count = var.is_organizational && length(var.management_group_ids) == 0 ? 1 : 0
6+
count = var.is_organizational ? 1 : 0
77
display_name = "Tenant Root Group"
88
}
99

@@ -12,13 +12,8 @@ data "azurerm_management_group" "management_groups" {
1212
name = each.value
1313
}
1414

15-
locals {
16-
subscriptions = toset(var.is_organizational && length(var.management_group_ids) == 0 ? data.azurerm_management_group.root_management_group[0].all_subscription_ids :
17-
flatten([for m in data.azurerm_management_group.management_groups : m.all_subscription_ids]))
18-
}
19-
2015
data "azurerm_subscription" "all_subscriptions" {
21-
for_each = toset(local.subscriptions)
16+
for_each = toset(local.all_mg_subscription_ids)
2217
subscription_id = each.value
2318
}
2419

modules/agentless-scanning/outputs.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ output "lighthouse_definition_display_id" {
66
output "service_principal_component_id" {
77
value = "${sysdig_secure_cloud_auth_account_component.azure_service_principal.type}/${sysdig_secure_cloud_auth_account_component.azure_service_principal.instance}"
88
description = "Component identifier of Service Principal created in Sysdig Backend for Agentless Scanning"
9-
depends_on = [ sysdig_secure_cloud_auth_account_component.azure_service_principal ]
9+
depends_on = [sysdig_secure_cloud_auth_account_component.azure_service_principal]
1010
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Azure supports up to 6 levels of management groups(do not include root management group), so we will create a module to get subscriptions using include/exclude filters for each level.
2+
# This is a workaround for the fact that Azure does not support recursive management group queries in TF.
3+
# http://learn.microsoft.com/en-us/azure/governance/management-groups/overview#important-facts-about-management-groups
4+
5+
# Rules for this module:
6+
# 1. We will exercise the module if 'exclude_management_groups' is set. We will recursively get all the management groups from the root management group id and exclude the ones in the exclude_management_groups list.
7+
# 2. We will exercise the module if 'include_management_groups' is set. We will recursively get all the management groups from the management group list and exclude the ones in the exclude_management_groups list.
8+
# 3. We will honor the include/exclude logic for subscriptions as well.
9+
10+
module "level0" {
11+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
12+
source = "../utils/granular-subscriptions"
13+
management_group_ids = length(var.include_management_groups) > 0 ? var.include_management_groups : [data.azurerm_management_group.root_management_group[0].name]
14+
exclude_management_groups = var.exclude_management_groups
15+
include_subscriptions = var.include_subscriptions
16+
exclude_subscriptions = var.exclude_subscriptions
17+
}
18+
19+
module "level1" {
20+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
21+
source = "../utils/granular-subscriptions"
22+
management_group_ids = module.level0[0].child_management_group_ids
23+
exclude_management_groups = var.exclude_management_groups
24+
include_subscriptions = var.include_subscriptions
25+
exclude_subscriptions = var.exclude_subscriptions
26+
}
27+
28+
module "level2" {
29+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
30+
source = "../utils/granular-subscriptions"
31+
management_group_ids = module.level1[0].child_management_group_ids
32+
exclude_management_groups = var.exclude_management_groups
33+
include_subscriptions = var.include_subscriptions
34+
exclude_subscriptions = var.exclude_subscriptions
35+
}
36+
37+
module "level3" {
38+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
39+
source = "../utils/granular-subscriptions"
40+
management_group_ids = module.level2[0].child_management_group_ids
41+
exclude_management_groups = var.exclude_management_groups
42+
include_subscriptions = var.include_subscriptions
43+
exclude_subscriptions = var.exclude_subscriptions
44+
}
45+
46+
module "level4" {
47+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
48+
source = "../utils/granular-subscriptions"
49+
management_group_ids = module.level3[0].child_management_group_ids
50+
exclude_management_groups = var.exclude_management_groups
51+
include_subscriptions = var.include_subscriptions
52+
exclude_subscriptions = var.exclude_subscriptions
53+
}
54+
55+
module "level5" {
56+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
57+
source = "../utils/granular-subscriptions"
58+
management_group_ids = module.level4[0].child_management_group_ids
59+
exclude_management_groups = var.exclude_management_groups
60+
include_subscriptions = var.include_subscriptions
61+
exclude_subscriptions = var.exclude_subscriptions
62+
}
63+
64+
module "level6" {
65+
count = var.is_organizational && (length(var.include_management_groups) > 0 || length(var.exclude_management_groups) > 0) ? 1 : 0
66+
source = "../utils/granular-subscriptions"
67+
management_group_ids = module.level5[0].child_management_group_ids
68+
exclude_management_groups = var.exclude_management_groups
69+
include_subscriptions = var.include_subscriptions
70+
exclude_subscriptions = var.exclude_subscriptions
71+
}

modules/agentless-scanning/variables.tf

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,40 @@ variable "is_organizational" {
1010
}
1111

1212
variable "management_group_ids" {
13-
description = "(Optional) List of Azure Management Group IDs. secure-for-cloud will be deployed to all the subscriptions under these management groups."
13+
description = <<-EOF
14+
TO BE DEPRECATED on 30th November, 2025: Please work with Sysdig to migrate to using `include_management_groups` instead.
15+
When set, restrict onboarding to a set of Azure Management Groups identifiers whose child management groups and subscriptions are to be onboarded.
16+
Default: onboard all management groups.
17+
EOF
1418
type = set(string)
1519
default = []
1620
}
1721

1822
variable "sysdig_secure_account_id" {
1923
type = string
2024
description = "ID of the Sysdig Cloud Account to enable Agentless Scanning for (incase of organization, ID of the Sysdig management account)"
21-
}
25+
}
26+
27+
variable "include_management_groups" {
28+
description = "(Optional) management groups to include for organization in the format '<management_group_id>' i.e: management_group_id_1"
29+
type = set(string)
30+
default = []
31+
}
32+
33+
variable "exclude_management_groups" {
34+
description = "(Optional) management groups to exclude for organization in the format '<management_group_id>' i.e: management_group_id_1"
35+
type = set(string)
36+
default = []
37+
}
38+
39+
variable "include_subscriptions" {
40+
description = "(Optional) subscription ids to include for organization i.e: 12345678-1234-1234-1234-123456789abc"
41+
type = set(string)
42+
default = []
43+
}
44+
45+
variable "exclude_subscriptions" {
46+
description = "(Optional) subscription ids to exclude for organization i.e: 12345678-1234-1234-1234-123456789abc"
47+
type = set(string)
48+
default = []
49+
}

0 commit comments

Comments
 (0)