Skip to content

Commit 1fb97b8

Browse files
Update Org onboarding to honor include/exclude (#39)
* Update Org onboarding to honor include/exclude Change summary: ---------------- - For Foundational onboarding, update the stackset deployment targets to honor the various include/exclude ous/accounts configuration input(s) provided by the user. - Added a section in README. * Handle account exclusions better * Remove comment * Move locals to separate tf * Honor include/exclude for all modules org installs * Fix local var to read set * add version and root id field * Update organizational.tf * Refactoring to work around unsupported AWS UNION filter - Modified the logic for include support: Inclusions with UNION filter don't work due to an AWS bug. Added temp change to then install resources on entire org. - Modified the logic for handling exclusions better and cleaner - Updated the test example snippets for all features (commercial installs) * Remove unncessary comment * Fix description comments * Fix var name reference * Keeping provider versions consistent --------- Co-authored-by: Jose Pablo Camacho <[email protected]>
1 parent b845be9 commit 1fb97b8

29 files changed

+952
-81
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,16 @@ Notice that:
6565

6666
<br/>
6767

68+
## Organizational Install Configurations
69+
70+
There are four new parameters to configure organizational deployments on the cloud for Sysdig Secure for Cloud :-
71+
1. `include_ouids` - List of AWS Organizational Unit IDs to deploy the Sysdig Secure for Cloud stack resources in.
72+
2. `exclude_ouids` - List of AWS Organizational Unit IDs to exclude deploying the Sysdig Secure for Cloud stack resources in.
73+
3. `include_accounts` - List of AWS Accounts to deploy the Sysdig Secure for Cloud stack resources in.
74+
4. `exclude_accounts` - List of AWS Accounts to exclude deploying the Sysdig Secure for Cloud stack resources in.
75+
76+
Note: module variable `organizational_unit_ids` / `org_units` will be DEPRECATED soon going forward. You can use `include_ouids` instead to achieve the same deployment outcome.
77+
6878
## Best practices
6979

7080
For contributing to existing modules or adding new modules, below are some of the best practices recommended :-

modules/agentless-scanning/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ No modules.
7070
| <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 |
7171
| <a name="input_tags"></a> [tags](#input\_tags) | sysdig secure-for-cloud tags. always include 'product' default tag for resource-group proper functioning | `map(string)` | <pre>{<br> "product": "sysdig-secure-for-cloud"<br>}</pre> | no |
7272
| <a name="input_timeout"></a> [timeout](#input\_timeout) | Default timeout values for create, update, and delete operations | `string` | `"30m"` | no |
73+
| <a name="input_include_ouids"></a> [include\_ouids](#input\_include\_ouids) | ouids to include for organization | `set(string)` | `[]` | no |
74+
| <a name="input_exclude_ouids"></a> [exclude\_ouids](#input\_exclude\_ouids) | ouids to exclude for organization | `set(string)` | `[]` | no |
75+
| <a name="input_include_accounts"></a> [include\_accounts](#input\_include\_accounts) | accounts to include for organization | `set(string)` | `[]` | no |
76+
| <a name="input_exclude_accounts"></a> [exclude\_accounts](#input\_exclude\_accounts) | accounts to exclude for organization | `set(string)` | `[]` | no |
77+
7378

7479
## Outputs
7580

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#----------------------------------------------------------
2+
# Fetch & compute required data for organizational install
3+
#----------------------------------------------------------
4+
5+
data "aws_organizations_organization" "org" {
6+
count = var.is_organizational ? 1 : 0
7+
}
8+
9+
locals {
10+
# fetch the AWS Root OU under org
11+
# As per https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started_concepts.html#organization-structure, there can be only one root
12+
root_org_unit = var.is_organizational ? [for root in data.aws_organizations_organization.org[0].roots : root.id] : []
13+
}
14+
15+
# *****************************************************************************************************************************************************
16+
# INCLUDE/EXCLUDE CONFIGURATION SUPPORT
17+
#
18+
# 1. Inclusions will always be handled for TF cloud provisioning.
19+
# NOTE:
20+
# Till AWS issue with UNION filter (https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-cloudformation/issues/100)
21+
# is fixed, we can't deploy using UNION filters for inclusions. As a workaround to ensure we don't skip any accounts, we deploy it to entire org.
22+
#
23+
# 2. We handle exclusions when only exclusion parameters are provided i.e out of all 4 configuration inputs,
24+
# a. only exclude_ouids are provided, OR
25+
# b. only exclude_accounts are provided, OR
26+
# c. only exclude_ouids AND exclude_accounts are provided
27+
# Else we ignore exclusions during cloud resource provisioning through TF. This is because AWS does not allow both operations - to include some
28+
# accounts and to exclude some. Hence, we will always prioritize include over exclude.
29+
#
30+
# 3. Sysdig however will honor all combinations of configuration inputs exactly as desired.
31+
# *****************************************************************************************************************************************************
32+
33+
#------------------------------------------------------------
34+
# Manage configurations to determine OU targets to deploy in
35+
#------------------------------------------------------------
36+
37+
locals {
38+
# OU CONFIGURATION (determine user provided org configuration)
39+
org_configuration = (
40+
# case1 - if no include/exclude ous provided, include entire org
41+
var.is_organizational && length(var.include_ouids) == 0 && length(var.exclude_ouids) == 0 ? (
42+
"entire_org"
43+
) : (
44+
# case2 - if only included ouids provided, include those ous only
45+
var.is_organizational && length(var.include_ouids) > 0 && length(var.exclude_ouids) == 0 ? (
46+
"included_ous_only"
47+
) : (
48+
# case3 - if only excluded ouids provided, exclude their accounts from rest of org
49+
var.is_organizational && length(var.include_ouids) == 0 && length(var.exclude_ouids) > 0 ? (
50+
"excluded_ous_only"
51+
) : (
52+
# case4 - if both include and exclude ouids are provided, includes override excludes
53+
var.is_organizational && length(var.include_ouids) > 0 && length(var.exclude_ouids) > 0 ? (
54+
"mixed_ous"
55+
) : ""
56+
)
57+
)
58+
)
59+
)
60+
61+
# switch cases for various user provided org configuration to be onboarded
62+
deployment_options = {
63+
entire_org = {
64+
org_units_to_deploy = local.root_org_unit
65+
}
66+
included_ous_only = {
67+
org_units_to_deploy = var.include_ouids
68+
}
69+
excluded_ous_only = {
70+
# onboard entire org and filter out all accounts in excluded OUs using account filter
71+
org_units_to_deploy = local.root_org_unit
72+
}
73+
mixed_ous = {
74+
# if both include and exclude ouids are provided, includes override excludes
75+
org_units_to_deploy = var.include_ouids
76+
}
77+
default = {
78+
org_units_to_deploy = local.root_org_unit
79+
}
80+
}
81+
82+
# final targets to deploy organizational resources in
83+
deployment_targets_ous = lookup(local.deployment_options, local.org_configuration, local.deployment_options.default)
84+
}
85+
86+
#-----------------------------------------------------------------
87+
# Manage configurations to determine account targets to deploy in
88+
#-----------------------------------------------------------------
89+
90+
# if only exclude_ouids are provided and as long as it isn't Root OU, fetch all their child accounts to filter exclusions
91+
data "aws_organizations_organizational_unit_descendant_accounts" "ou_accounts_to_exclude" {
92+
for_each = local.org_configuration == "excluded_ous_only" && !contains(var.exclude_ouids, local.root_org_unit[0]) ? var.exclude_ouids : []
93+
parent_id = each.key
94+
}
95+
96+
locals {
97+
# ACCOUNTS CONFIGURATION (determine user provided accounts configuration)
98+
accounts_configuration = (
99+
# case1 - if only included accounts provided, include those accts as well
100+
var.is_organizational && length(var.include_accounts) > 0 && length(var.exclude_accounts) == 0 ? (
101+
"UNION"
102+
) : (
103+
# case2 - if only excluded accounts or only excluded ouids provided, exclude those accounts
104+
var.is_organizational && length(var.include_accounts) == 0 && ( length(var.exclude_accounts) > 0 || local.org_configuration == "excluded_ous_only" ) ? (
105+
"DIFFERENCE"
106+
) : (
107+
# case3 - if both include and exclude accounts are provided, includes override excludes
108+
var.is_organizational && length(var.include_accounts) > 0 && length(var.exclude_accounts) > 0 ? (
109+
"MIXED"
110+
) : ""
111+
)
112+
)
113+
)
114+
115+
ou_accounts_to_exclude = flatten([ for ou_accounts in data.aws_organizations_organizational_unit_descendant_accounts.ou_accounts_to_exclude: [ ou_accounts.accounts[*].id ] ])
116+
accounts_to_exclude = setunion(local.ou_accounts_to_exclude, var.exclude_accounts)
117+
118+
# switch cases for various user provided accounts configuration to be onboarded
119+
deployment_account_options = {
120+
UNION = {
121+
accounts_to_deploy = var.include_accounts
122+
account_filter_type = "UNION"
123+
}
124+
DIFFERENCE = {
125+
accounts_to_deploy = local.accounts_to_exclude
126+
account_filter_type = "DIFFERENCE"
127+
}
128+
MIXED = {
129+
accounts_to_deploy = var.include_accounts
130+
account_filter_type = "UNION"
131+
}
132+
default = {
133+
# default when neither of include/exclude accounts are provided
134+
accounts_to_deploy = []
135+
account_filter_type = "NONE"
136+
}
137+
}
138+
139+
# list of accounts to deploy organizational resources in
140+
deployment_targets_accounts = lookup(local.deployment_account_options, local.accounts_configuration, local.deployment_account_options.default)
141+
}
142+
143+
# -----------------------------------------------------------------------------------------------------
144+
# Remove below conditional once AWS issue is fixed -
145+
# https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-cloudformation/issues/100
146+
# -----------------------------------------------------------------------------------------------------
147+
locals {
148+
# XXX: due to AWS bug of not having UNION filter fully working, there is no way to add those extra accounts requested.
149+
# to not miss out on those extra accounts, deploy the cloud resources across entire org and noop the UNION filter.
150+
# i.e till we can't deploy UNION, we deploy it all
151+
deployment_targets_org_units = local.deployment_targets_accounts.account_filter_type == "UNION" ? local.root_org_unit : local.deployment_targets_ous.org_units_to_deploy
152+
deployment_targets_accounts_filter = local.deployment_targets_accounts.account_filter_type == "UNION" ? "NONE" : local.deployment_targets_accounts.account_filter_type
153+
}

modules/agentless-scanning/organizational.tf

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,6 @@
77
# - an Alias by the same name for the respective key, in each region of region list.
88
#-----------------------------------------------------------------------------------------------------------------------
99

10-
data "aws_organizations_organization" "org" {
11-
count = var.is_organizational ? 1 : 0
12-
}
13-
14-
locals {
15-
organizational_unit_ids = var.is_organizational && length(var.org_units) == 0 ? [for root in data.aws_organizations_organization.org[0].roots : root.id] : toset(var.org_units)
16-
}
17-
1810
#-----------------------------------------------------------------------------------------------------------------------
1911
# stackset and stackset instance deployed for all accounts in all organization units
2012
# - IAM Role
@@ -196,7 +188,9 @@ resource "aws_cloudformation_stack_set_instance" "ou_stackset_instance" {
196188

197189
stack_set_name = aws_cloudformation_stack_set.ou_resources_stackset[0].name
198190
deployment_targets {
199-
organizational_unit_ids = local.organizational_unit_ids
191+
organizational_unit_ids = local.deployment_targets_org_units
192+
accounts = local.deployment_targets_accounts_filter == "NONE" ? null : local.deployment_targets_accounts.accounts_to_deploy
193+
account_filter_type = local.deployment_targets_accounts_filter
200194
}
201195
operation_preferences {
202196
max_concurrent_percentage = 100

modules/agentless-scanning/variables.tf

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ variable "is_organizational" {
3131
}
3232

3333
variable "org_units" {
34-
description = "(Optional) List of Organization Unit IDs in which to setup Agentless Scanning. By default, Agentless Scanning will be setup in all accounts within the Organization. This field is ignored if `is_organizational = false`"
34+
description = <<-EOF
35+
DEPRECATED: Defaults to `[]`, use `include_ouids` instead.
36+
When set, list of Organization Unit IDs to setup Agentless Scanning. By default, Agentless Scanning will be setup in all accounts within the Organization."
37+
EOF
3538
type = set(string)
3639
default = []
3740
}
@@ -81,4 +84,28 @@ variable "failure_tolerance_percentage" {
8184
variable "sysdig_secure_account_id" {
8285
type = string
8386
description = "ID of the Sysdig Cloud Account to enable Agentless Scanning for (incase of organization, ID of the Sysdig management account)"
87+
}
88+
89+
variable "include_ouids" {
90+
description = "(Optional) ouids to include for organization"
91+
type = set(string)
92+
default = []
93+
}
94+
95+
variable "exclude_ouids" {
96+
description = "(Optional) ouids to exclude for organization"
97+
type = set(string)
98+
default = []
99+
}
100+
101+
variable "include_accounts" {
102+
description = "(Optional) accounts to include for organization"
103+
type = set(string)
104+
default = []
105+
}
106+
107+
variable "exclude_accounts" {
108+
description = "(Optional) accounts to exclude for organization"
109+
type = set(string)
110+
default = []
84111
}

modules/config-posture/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ If instrumenting an AWS Gov account/organization, IAM policies and resources wil
1919
|---------------------------------------------------------------------------|-----------|
2020
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
2121
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.60.0 |
22-
| <a name="requirement_sysdig"></a> [sysdig](#requirement\_sysdig) | ~>1.39 |
22+
| <a name="requirement_sysdig"></a> [sysdig](#requirement\_sysdig) | ~>1.48 |
2323

2424
## Providers
2525

0 commit comments

Comments
 (0)