Skip to content

Commit aec1584

Browse files
authored
feat: Add organizational cloud-scanning (#20)
* feat: Add organizational cloud-scanning * docs(organizational): Update documentation diagram
1 parent 256e464 commit aec1584

File tree

11 files changed

+158
-63
lines changed

11 files changed

+158
-63
lines changed

examples/organizational/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ Notice that:
7676
| Name | Source | Version |
7777
|------|--------|---------|
7878
| <a name="module_cloud_connector"></a> [cloud\_connector](#module\_cloud\_connector) | ../../modules/services/cloud-connector | |
79+
| <a name="module_cloud_scanning"></a> [cloud\_scanning](#module\_cloud\_scanning) | ../../modules/services/cloud-scanning | |
7980
| <a name="module_cloudtrail"></a> [cloudtrail](#module\_cloudtrail) | ../../modules/infrastructure/cloudtrail | |
81+
| <a name="module_codebuild"></a> [codebuild](#module\_codebuild) | ../../modules/infrastructure/codebuild | |
8082
| <a name="module_ecs_fargate_cluster"></a> [ecs\_fargate\_cluster](#module\_ecs\_fargate\_cluster) | ../../modules/infrastructure/ecs-fargate-cluster | |
8183
| <a name="module_resource_group_master"></a> [resource\_group\_master](#module\_resource\_group\_master) | ../../modules/infrastructure/resource-group | |
8284
| <a name="module_resource_group_secure_for_cloud_member"></a> [resource\_group\_secure\_for\_cloud\_member](#module\_resource\_group\_secure\_for\_cloud\_member) | ../../modules/infrastructure/resource-group | |
36.7 KB
Loading

examples/organizational/diagram-org.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
# diagrams as code vía https://diagrams.mingrammer.com
2-
from diagrams import Diagram, Cluster, Diagram, Edge, Node
3-
from diagrams.custom import Custom
4-
from diagrams.aws.general import General
5-
from diagrams.aws.management import Cloudtrail
6-
from diagrams.aws.storage import S3, SimpleStorageServiceS3Bucket
7-
from diagrams.aws.integration import SNS
8-
from diagrams.aws.integration import SQS
2+
from diagrams import Cluster, Diagram, Edge, Node
93
from diagrams.aws.compute import ElasticContainerServiceService
10-
from diagrams.aws.security import IAMRole,IAM
11-
from diagrams.aws.management import Cloudwatch
12-
4+
from diagrams.aws.devtools import Codebuild
5+
from diagrams.aws.general import General
6+
from diagrams.aws.integration import SNS, SQS
7+
from diagrams.aws.management import Cloudtrail, Cloudwatch
8+
from diagrams.aws.security import IAM, IAMRole
9+
from diagrams.aws.storage import S3
10+
from diagrams.custom import Custom
1311

1412
diagram_attr = {
1513
"pad":"0.25"
@@ -23,14 +21,14 @@
2321

2422
event_color="firebrick"
2523

26-
with Diagram("Sysdig Secure for Cloud{}(organizational usecase)".format("\n"), graph_attr=diagram_attr, filename="diagram-org", show=True):
24+
with Diagram("Sysdig Secure for Cloud\n(organizational usecase)", graph_attr=diagram_attr, filename="diagram-org", show=True):
2725

2826
with Cluster("AWS organization"):
2927

30-
with Cluster("member account (main targets)", graph_attr={"bgcolor":"lightblue"}):
31-
member_accounts = [General("account-1"),General("..."),General("account-n")]
28+
with Cluster("member accounts (main targets)", graph_attr={"bgcolor":"lightblue"}):
29+
member_accounts = [General("account-1"), General("account-2"), General("..."), General("account-n")]
3230

33-
org_member_role = IAMRole("OrganizationAccountAccessRole\ncreated by AWS for org. member accounts", **role_attr)
31+
org_member_role = IAMRole("OrganizationAccountAccessRole\n(created by AWS for org. member accounts)", **role_attr)
3432

3533

3634
with Cluster("master account"):
@@ -53,18 +51,22 @@
5351

5452
with Cluster("member account (secure for cloud)", graph_attr={"bgcolor":"seashell2"}):
5553

56-
org_member_role = IAMRole("OrganizationAccountAccessRole\ncreated by AWS for org. member accounts", **role_attr)
54+
org_member_role = IAMRole("OrganizationAccountAccessRole\n(created by AWS for org. member accounts)", **role_attr)
5755

5856
with Cluster("ecs-cluster"):
5957
cloud_connector = ElasticContainerServiceService("cloud-connector")
58+
cloud_scanning = ElasticContainerServiceService("cloud-scanning")
6059

6160
sqs = SQS("cloudtrail-sqs")
6261
s3_config = S3("cloud-connector-config")
6362
cloudwatch = Cloudwatch("cloudwatch\nlogs and alarms")
63+
codebuild = Codebuild("codebuild project")
6464

6565
sqs << Edge(color=event_color) << cloud_connector
66+
sqs << Edge(color=event_color) << cloud_scanning
6667
cloud_connector - s3_config
6768
cloud_connector >> cloudwatch
69+
cloud_scanning >> codebuild
6870

6971

7072
member_accounts >> Edge(color=event_color, style="dashed") >> cloudtrail
@@ -76,3 +78,4 @@
7678
sds = Custom("Sysdig Secure", "../../resources/diag-sysdig-icon.png")
7779

7880
cloud_connector >> sds
81+
codebuild >> sds

examples/organizational/main.tf

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ module "ssm" {
6868
}
6969

7070

71-
7271
#
7372
# cloud-connector
7473
#
@@ -99,7 +98,6 @@ module "cloud_connector" {
9998
}
10099

101100

102-
103101
#
104102
# cloud-bench
105103
# WIP
@@ -122,40 +120,45 @@ module "cloud_connector" {
122120

123121
#
124122
# cloud-scanning
125-
# WIP
126123
#
124+
## FIXME? if this is a non-shared resource, move its usage to scanning service?
125+
module "codebuild" {
126+
providers = {
127+
aws = aws.member
128+
}
129+
source = "../../modules/infrastructure/codebuild"
130+
name = var.name
131+
secure_api_token_secret_name = module.ssm.secure_api_token_secret_name
132+
depends_on = [module.ssm]
133+
}
127134

135+
module "cloud_scanning" {
136+
providers = {
137+
aws = aws.member
138+
}
128139

129-
## FIXME? if this is a non-shared resource, move its usage to scanning service?
130-
#module "codebuild" {
131-
# source = "../../modules/infrastructure/codebuild"
132-
# name = var.name
133-
# secure_api_token_secret_name = module.ssm.secure_api_token_secret_name
134-
# depends_on = [module.ssm]
135-
#}
136-
#
140+
source = "../../modules/services/cloud-scanning"
141+
name = "${var.name}-cloudscanning"
137142

143+
sysdig_secure_endpoint = var.sysdig_secure_endpoint
144+
secure_api_token_secret_name = module.ssm.secure_api_token_secret_name
138145

139-
#module "cloud_scanning" {
140-
# providers = {
141-
# aws = aws.member
142-
# }
143-
#
144-
# source = "../../modules/services/cloud-scanning"
145-
# name = "${var.name}-cloudscanning"
146-
#
147-
# sysdig_secure_endpoint = var.sysdig_secure_endpoint
148-
# secure_api_token_secret_name = module.ssm.secure_api_token_secret_name
149-
#
150-
# build_project_arn = module.codebuild.project_arn
151-
# build_project_name = module.codebuild.project_name
152-
#
153-
# sns_topic_arn = module.cloudtrail.sns_topic_arn
154-
#
155-
# ecs_cluster = module.ecs_fargate_cluster.id
156-
# vpc_id = module.ecs_fargate_cluster.vpc_id
157-
# vpc_subnets = module.ecs_fargate_cluster.vpc_subnets
158-
#
159-
# tags = var.tags
160-
# depends_on = [module.cloudtrail, module.ecs_fargate_cluster, module.codebuild, module.ssm]
161-
#}
146+
build_project_arn = module.codebuild.project_arn
147+
build_project_name = module.codebuild.project_name
148+
149+
is_organizational = true
150+
organizational_config = {
151+
sysdig_secure_for_cloud_role_arn = module.secure_for_cloud_role.sysdig_secure_for_cloud_role_arn
152+
organizational_role_per_account = "OrganizationAccountAccessRole"
153+
scanning_ecs_task_role_name = aws_iam_role.connector_ecs_task.name
154+
}
155+
156+
sns_topic_arn = module.cloudtrail.sns_topic_arn
157+
158+
ecs_cluster = module.ecs_fargate_cluster.id
159+
vpc_id = module.ecs_fargate_cluster.vpc_id
160+
vpc_subnets = module.ecs_fargate_cluster.vpc_subnets
161+
162+
tags = var.tags
163+
depends_on = [module.cloudtrail, module.ecs_fargate_cluster, module.codebuild, module.ssm]
164+
}

modules/infrastructure/organizational/secure-for-cloud-role/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ No modules.
2626
|------|------|
2727
| [aws_iam_role.secure_for_cloud_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
2828
| [aws_iam_role_policy.enable_assume_secure_for_cloud_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
29+
| [aws_iam_role_policy.sysdig_secure_for_cloud_role_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
2930
| [aws_iam_role_policy.sysdig_secure_for_cloud_role_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
3031
| [aws_iam_policy_document.enable_assume_secure_for_cloud_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
32+
| [aws_iam_policy_document.sysdig_secure_for_cloud_role_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
3133
| [aws_iam_policy_document.sysdig_secure_for_cloud_role_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
3234
| [aws_iam_policy_document.sysdig_secure_for_cloud_role_trusted](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
3335
| [aws_iam_role.ecs_task_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_role) | data source |
@@ -39,6 +41,7 @@ No modules.
3941
| <a name="input_cloudconnector_ecs_task_role_name"></a> [cloudconnector\_ecs\_task\_role\_name](#input\_cloudconnector\_ecs\_task\_role\_name) | cloudconnector ecs task role name | `string` | n/a | yes |
4042
| <a name="input_cloudtrail_s3_arn"></a> [cloudtrail\_s3\_arn](#input\_cloudtrail\_s3\_arn) | Cloudtrail S3 bucket ARN | `string` | n/a | yes |
4143
| <a name="input_name"></a> [name](#input\_name) | Name for the Cloud Connector deployment | `string` | `"sysdig-secure-for-cloud"` | no |
44+
| <a name="input_organizational_role_per_account"></a> [organizational\_role\_per\_account](#input\_organizational\_role\_per\_account) | Name of the organizational role deployed by AWS in each account of the organization | `string` | `"OrganizationAccountAccessRole"` | no |
4245
| <a name="input_tags"></a> [tags](#input\_tags) | sysdig secure-for-cloud tags | `map(string)` | <pre>{<br> "product": "sysdig-secure-for-cloud"<br>}</pre> | no |
4346

4447
## Outputs

modules/infrastructure/organizational/secure-for-cloud-role/main.tf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,21 @@ data "aws_iam_policy_document" "sysdig_secure_for_cloud_role_s3" {
7474
]
7575
}
7676
}
77+
78+
79+
resource "aws_iam_role_policy" "sysdig_secure_for_cloud_role_assume_role" {
80+
name = "${var.name}-AllowAssumeRoleInChildAccounts"
81+
role = aws_iam_role.secure_for_cloud_role.id
82+
policy = data.aws_iam_policy_document.sysdig_secure_for_cloud_role_assume_role.json
83+
}
84+
data "aws_iam_policy_document" "sysdig_secure_for_cloud_role_assume_role" {
85+
statement {
86+
effect = "Allow"
87+
actions = [
88+
"sts:AssumeRole",
89+
]
90+
resources = [
91+
"arn:aws:iam::*:role/${var.organizational_role_per_account}"
92+
]
93+
}
94+
}

modules/infrastructure/organizational/secure-for-cloud-role/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ variable "name" {
1818
description = "Name for the Cloud Connector deployment"
1919
}
2020

21+
variable "organizational_role_per_account" {
22+
type = string
23+
default = "OrganizationAccountAccessRole"
24+
description = "Name of the organizational role deployed by AWS in each account of the organization"
25+
}
26+
2127
variable "tags" {
2228
type = map(string)
2329
description = "sysdig secure-for-cloud tags"

modules/services/cloud-scanning/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ No modules.
5454
| [aws_iam_policy_document.task_definition_reader](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
5555
| [aws_iam_policy_document.task_read_parameters](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
5656
| [aws_iam_policy_document.trigger_scan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
57+
| [aws_iam_role.task_inherited](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_role) | data source |
5758
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
5859
| [aws_ssm_parameter.sysdig_secure_api_token](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source |
5960

@@ -71,7 +72,10 @@ No modules.
7172
| <a name="input_cloudwatch_log_retention"></a> [cloudwatch\_log\_retention](#input\_cloudwatch\_log\_retention) | Days to keep logs for CloudScanning | `number` | `5` | no |
7273
| <a name="input_extra_env_vars"></a> [extra\_env\_vars](#input\_extra\_env\_vars) | Extra environment variables for the Cloud Scanning deployment | `map(string)` | `{}` | no |
7374
| <a name="input_image"></a> [image](#input\_image) | Image of the cloud scanning to deploy | `string` | `"quay.io/sysdig/cloud-scanning:latest"` | no |
75+
| <a name="input_is_organizational"></a> [is\_organizational](#input\_is\_organizational) | whether secure-for-cloud should be deployed in an organizational setup | `bool` | `false` | no |
7476
| <a name="input_name"></a> [name](#input\_name) | Name for the Cloud Scanning deployment | `string` | `"sysdig-secure-for-cloudscanning"` | no |
77+
| <a name="input_organizational_config"></a> [organizational\_config](#input\_organizational\_config) | organizational\_config. following attributes must be given<br><ul><br> <li>`sysdig_secure_for_cloud_role_arn` for cloud-connector assumeRole in order to read cloudtrail s3 events</li><br> <li>`scanning_ecs_task_role_name` which has been granted trusted-relationship over the secure\_for\_cloud\_role</li><br> <li>`organizational_role_per_account` is the name of the organizational role deployed by AWS in each account of the organization</li><br></ul> | <pre>object({<br> sysdig_secure_for_cloud_role_arn = string<br> organizational_role_per_account = string<br> scanning_ecs_task_role_name = string<br> })</pre> | <pre>{<br> "organizational_role_per_account": "",<br> "scanning_ecs_task_role_name": "",<br> "sysdig_secure_for_cloud_role_arn": ""<br>}</pre> | no |
78+
| <a name="input_scanning_ecs_task_role_name"></a> [scanning\_ecs\_task\_role\_name](#input\_scanning\_ecs\_task\_role\_name) | Default ecs cloudscanning task role name | `string` | `"scanning-ECSTaskRole"` | no |
7579
| <a name="input_sysdig_secure_endpoint"></a> [sysdig\_secure\_endpoint](#input\_sysdig\_secure\_endpoint) | Sysdig Secure API endpoint | `string` | `"https://secure.sysdig.com"` | no |
7680
| <a name="input_tags"></a> [tags](#input\_tags) | sysdig secure-for-cloud tags | `map(string)` | <pre>{<br> "product": "sysdig-secure-for-cloud"<br>}</pre> | no |
7781
| <a name="input_verify_ssl"></a> [verify\_ssl](#input\_verify\_ssl) | true/false to determine ssl secure connection verification | `bool` | `true` | no |

modules/services/cloud-scanning/ecs-service-security.tf

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
data "aws_ssm_parameter" "sysdig_secure_api_token" {
22
name = var.secure_api_token_secret_name
33
}
4+
5+
locals {
6+
ecs_task_role_id = var.is_organizational ? data.aws_iam_role.task_inherited[0].id : aws_iam_role.task[0].id
7+
ecs_task_role_arn = var.is_organizational ? data.aws_iam_role.task_inherited[0].arn : aws_iam_role.task[0].arn
8+
ecs_task_role_name_suffix = var.is_organizational ? var.organizational_config.scanning_ecs_task_role_name : var.scanning_ecs_task_role_name
9+
}
10+
411
#---------------------------------
512
# task role
13+
# notes
14+
# - duplicated in /examples/organizational/utils.tf, where root lvl role is created, to avoid cyclic dependencies
615
#---------------------------------
7-
16+
data "aws_iam_role" "task_inherited" {
17+
count = var.is_organizational ? 1 : 0
18+
name = var.organizational_config.scanning_ecs_task_role_name
19+
}
820
resource "aws_iam_role" "task" {
9-
name = "${var.name}-ECSTaskRole"
10-
assume_role_policy = data.aws_iam_policy_document.task_assume_role.json
21+
count = var.is_organizational ? 0 : 1
22+
name = "${var.name}-${local.ecs_task_role_name_suffix}"
23+
assume_role_policy = data.aws_iam_policy_document.task_assume_role[0].json
1124
path = "/"
1225
tags = var.tags
1326
}
1427
data "aws_iam_policy_document" "task_assume_role" {
28+
count = var.is_organizational ? 0 : 1
1529
statement {
1630
effect = "Allow"
1731
principals {
@@ -24,7 +38,7 @@ data "aws_iam_policy_document" "task_assume_role" {
2438

2539
resource "aws_iam_role_policy" "task" {
2640
name = "${var.name}-TaskRolePolicy"
27-
role = aws_iam_role.task.id
41+
role = local.ecs_task_role_id
2842
policy = data.aws_iam_policy_document.iam_role_task_role_policy.json
2943
}
3044
data "aws_iam_policy_document" "iam_role_task_role_policy" {
@@ -46,7 +60,7 @@ data "aws_iam_policy_document" "iam_role_task_role_policy" {
4660

4761
resource "aws_iam_role_policy" "trigger_scan" {
4862
name = "${var.name}-TriggerScan"
49-
role = aws_iam_role.task.id
63+
role = local.ecs_task_role_id
5064
policy = data.aws_iam_policy_document.trigger_scan.json
5165
}
5266
data "aws_iam_policy_document" "trigger_scan" {
@@ -61,7 +75,7 @@ data "aws_iam_policy_document" "trigger_scan" {
6175

6276
resource "aws_iam_role_policy" "task_definition_reader" {
6377
name = "TaskDefinitionReader"
64-
role = aws_iam_role.task.id
78+
role = local.ecs_task_role_id
6579
policy = data.aws_iam_policy_document.task_definition_reader.json
6680
}
6781
data "aws_iam_policy_document" "task_definition_reader" {
@@ -76,7 +90,7 @@ data "aws_iam_policy_document" "task_definition_reader" {
7690

7791
resource "aws_iam_role_policy" "secrets_reader" {
7892
name = "SecretsReader"
79-
role = aws_iam_role.task.id
93+
role = local.ecs_task_role_id
8094
policy = data.aws_iam_policy_document.secrets_reader.json
8195
}
8296
data "aws_iam_policy_document" "secrets_reader" {
@@ -92,7 +106,7 @@ data "aws_iam_policy_document" "secrets_reader" {
92106

93107
resource "aws_iam_role_policy" "ecr_reader" {
94108
name = "ECRReader"
95-
role = aws_iam_role.task.id
109+
role = local.ecs_task_role_id
96110
policy = data.aws_iam_policy_document.ecr_reader.json
97111
}
98112
data "aws_iam_policy_document" "ecr_reader" {
@@ -117,7 +131,6 @@ data "aws_iam_policy_document" "ecr_reader" {
117131
}
118132

119133

120-
121134
#---------------------------------
122135
# execution role
123136
# This role is required by tasks to pull container images and publish container logs to Amazon CloudWatch on your behalf.

modules/services/cloud-scanning/ecs-service.tf

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ resource "aws_ecs_task_definition" "task_definition" {
2222
requires_compatibilities = ["FARGATE"]
2323
network_mode = "awsvpc"
2424
execution_role_arn = aws_iam_role.execution.arn # ARN of the task execution role that the Amazon ECS container agent and the Docker daemon can assume
25-
task_role_arn = aws_iam_role.task.arn # ARN of IAM role that allows your Amazon ECS container task to make calls to other AWS resource-group.
25+
task_role_arn = local.ecs_task_role_arn # ARN of IAM role that allows your Amazon ECS container task to make calls to other AWS resource-group.
2626
cpu = "256"
2727
memory = "512"
2828

@@ -84,9 +84,21 @@ locals {
8484
name = "SECURE_API_TOKEN_SECRET"
8585
value = var.secure_api_token_secret_name
8686
}
87-
], flatten([for env_key, env_value in var.extra_env_vars : [{
87+
],
88+
local.task_organizational_env_vars,
89+
[for env_key, env_value in var.extra_env_vars : {
8890
name = env_key,
8991
value = env_value
90-
}]])
92+
}]
9193
)
94+
task_organizational_env_vars = [
95+
{
96+
name = "MASTER_ORGANIZATION_ROLE"
97+
value = var.is_organizational ? var.organizational_config.sysdig_secure_for_cloud_role_arn : ""
98+
},
99+
{
100+
name = "ORGANIZATIONAL_ROLE_PER_ACCOUNT"
101+
value = var.is_organizational ? var.organizational_config.organizational_role_per_account : ""
102+
}
103+
]
92104
}

0 commit comments

Comments
 (0)