Skip to content

Commit 869630a

Browse files
feat(vm): add vm modular support
1 parent 4d60c2d commit 869630a

File tree

8 files changed

+453
-0
lines changed

8 files changed

+453
-0
lines changed

modules/agentless-scan/README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# GCP Agentless Scanning Module
2+
3+
This Module creates the resources required to scan hosts on Google Cloud Projects. Before applying the changes defined
4+
in this module, the following operations need to be performed on the target GCP environment:
5+
6+
- The APIs needed for the CDR/CIEM feature are listed below:
7+
- Compute Engine API
8+
9+
- The following resources will be created in each instrumented project:
10+
- For the **Resource Discovery**: Enable Sysdig to authenticate through a Workload Identity Pool (requires provider,
11+
service account, role, and related bindings) in order to be able to discover the VPC/Instance/Volumes.
12+
- For the **Host Data Extraction**: Enable Sysdig to create a disk copy on our SaaS platform, to be able to extract
13+
the data required for security assessment.
14+
15+
This module will also deploy a Service Principal Component in Sysdig Backend for onboarded Sysdig Cloud Account.
16+
17+
## Single Project Setup
18+
19+
![permission_diagram_single](./permissions_diagram_single.png)
20+
21+
## Organizational Setup
22+
23+
Set `is_organizatinal=true` together with the `organization_domain=<domain>`.
24+
![permission_diagram_org](./permissions_diagram_org.png)
25+
26+
## Requirements
27+
28+
| Name | Version |
29+
|---------------------------------------------------------------------------|-----------|
30+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
31+
| <a name="requirement_google"></a> [google](#requirement\_google) | >= 4.21.0 |
32+
| <a name="requirement_sysdig"></a> [sysdig](#requirement\_sysdig) | >= 1.34.0 |
33+
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.1 |
34+
35+
## Providers
36+
37+
| Name | Version |
38+
|---------------------------------------------------------------------------|-----------|
39+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
40+
| <a name="requirement_google"></a> [google](#requirement\_google) | >= 4.21.0 |
41+
| <a name="requirement_sysdig"></a> [sysdig](#requirement\_sysdig) | >= 1.34.0 |
42+
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.1 |
43+
44+
## Modules
45+
46+
No modules.
47+
48+
## Resources
49+
50+
| Name | Type |
51+
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
52+
| [random_id.suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
53+
| [google_iam_workload_identity_pool.agentless](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool) | resource |
54+
| [google_iam_workload_identity_pool_provider.agentless](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider) | resource |
55+
| [google_iam_workload_identity_pool_provider.agentless_gcp](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider) | resource |
56+
| [google_organization_iam_binding.admin_account_iam](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/organization_iam_binding) | resource |
57+
| [google_organization_iam_binding.controller_custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/organization_iam_binding) | resource |
58+
| [google_organization_iam_custom_role.controller](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/organization_iam_custom_role) | resource |
59+
| [google_organization_iam_custom_role.worker_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/organization_iam_custom_role) | resource |
60+
| [google_project_iam_binding.admin_account_iam](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_binding) | resource |
61+
| [google_project_iam_binding.controller_custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_binding) | resource |
62+
| [google_project_iam_custom_role.controller](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_custom_role) | resource |
63+
| [google_project_iam_custom_role.worker_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_custom_role) | resource |
64+
| [google_service_account.controller](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource |
65+
| [google_service_account_iam_member.controller_custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_member) | resource |
66+
| [google_service_account_iam_member.controller_custom_gcp](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_member) | resource |
67+
| [google_organization.org](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/organization) | data source |
68+
| [google_project.project](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/project) | data source |
69+
| [sysdig_secure_trusted_cloud_identity.trusted_identity](https://registry.terraform.io/providers/sysdiglabs/sysdig/latest/docs/data-sources/secure_trusted_cloud_identity) | data source |
70+
71+
## Inputs
72+
73+
| Name | Description | Type | Default | Required |
74+
|----------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|-----------------------------|:--------:|
75+
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | GCP Project ID | `string` | n/a | yes |
76+
| <a name="input_is_organizational"></a> [is\_organizational](#input\_is\_organizational) | Optional. Determines whether module must scope whole organization. Otherwise single project will be scoped | `bool` | `false` | no |
77+
| <a name="input_organization_domain"></a> [organization\_domain](#input\_organization\_domain) | Optional. If `is_organizational=true` is set, its mandatory to specify this value, with the GCP Organization domain. e.g. sysdig.com | `string` | `null` | no |
78+
| <a name="input_role_name"></a> [role\_name](#input\_role\_name) | Optional. Name for the Worker Role on the Customer infrastructure | `string` | `"SysdigAgentlessHostRole"` | no |
79+
| <a name="input_sysdig_account_id"></a> [sysdig\_account\_id](#input\_sysdig\_account\_id) | Sysdig provided GCP Account designated for the host scan.<br/>One of `sysdig_backend` or `sysdig_account_id`must be provided | `string` | `null` | no |
80+
| <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 integration for (in case of organization, ID of the Sysdig management account) | `string` | `null` | no |
81+
| <a name="input_suffix"></a> [suffix](#input\_suffix) | Optional. Suffix word to enable multiple deployments with different naming<br/>(Workload Identity Pool and Providers have a soft deletion on Google Platform that will disallow name re-utilization)<br/>By default a random value will be autogenerated. | `string` | `null` | no |
82+
83+
## Outputs
84+
85+
| Name | Description |
86+
|--------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
87+
| <a name="agentless_scan_component_id"></a> [agentless\_scan\_component\_id](#agentless\_scan\_component\_id) | Component identifier of Agentless Scan integration created in Sysdig Backend for Log Ingestion |
88+
89+
## Authors
90+
91+
Module is maintained by [Sysdig](https://sysdig.com).
92+
93+
## License
94+
95+
Apache 2 Licensed. See LICENSE for full details.

modules/agentless-scan/main.tf

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#-----------------------------------------------------------------------------------------
2+
# Fetch the data sources
3+
#-----------------------------------------------------------------------------------------
4+
data "sysdig_secure_agentless_scanning_assets" "assets" {}
5+
6+
#-----------------------------------------------------------------------------------------
7+
# These locals indicate the suffix to create unique name for resources and permissions
8+
#-----------------------------------------------------------------------------------------
9+
locals {
10+
suffix = var.suffix == null ? random_id.suffix[0].hex : var.suffix
11+
host_discovery_permissions = [
12+
# networks
13+
"compute.networks.list",
14+
"compute.networks.get",
15+
# instances
16+
"compute.instances.list",
17+
"compute.instances.get",
18+
# disks
19+
"compute.disks.list",
20+
"compute.disks.get",
21+
# workload identity federation
22+
"iam.serviceAccounts.getAccessToken",
23+
]
24+
host_scan_permissions = [
25+
# general stuff
26+
"compute.zoneOperations.get",
27+
# disks
28+
"compute.disks.get",
29+
"compute.disks.useReadOnly",
30+
]
31+
}
32+
33+
#-----------------------------------------------------------------------------------------------------------------------
34+
# A random resource is used to generate unique Agentless Scan name suffix for resources.
35+
# This prevents conflicts when recreating an Agentless Scan resources with the same name.
36+
#-----------------------------------------------------------------------------------------------------------------------
37+
resource "random_id" "suffix" {
38+
count = var.suffix == null ? 1 : 0
39+
byte_length = 3
40+
}
41+
42+
43+
resource "google_service_account" "controller" {
44+
project = var.project_id
45+
account_id = "sysdig-ahs-${local.suffix}"
46+
display_name = "Sysdig Agentless Host Scanning"
47+
}
48+
49+
#-----------------------------------------------------------------------------------------------------------------------
50+
# Configure Workload Identity Federation for auth
51+
# See https://cloud.google.com/iam/docs/access-resources-aws
52+
#-----------------------------------------------------------------------------------------------------------------------
53+
54+
resource "google_iam_workload_identity_pool" "agentless" {
55+
workload_identity_pool_id = "sysdig-ahs-${local.suffix}"
56+
}
57+
58+
resource "google_iam_workload_identity_pool_provider" "agentless" {
59+
count = data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id != null ? 1 : 0
60+
61+
lifecycle {
62+
precondition {
63+
condition = (data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id != null && var.sysdig_account_id == null)
64+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
65+
}
66+
}
67+
68+
workload_identity_pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id
69+
workload_identity_pool_provider_id = "sysdig-ahs-${local.suffix}"
70+
display_name = "Sysdig Agentless Controller"
71+
description = "AWS identity pool provider for Sysdig Secure Agentless Host Scanning"
72+
disabled = false
73+
74+
attribute_condition = "attribute.aws_account==\"${data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id}\""
75+
76+
attribute_mapping = {
77+
"google.subject" = "assertion.arn"
78+
"attribute.aws_account" = "assertion.account"
79+
"attribute.role" = "assertion.arn.extract(\"/assumed-role/{role}/\")"
80+
"attribute.session" = "assertion.arn.extract(\"/assumed-role/{role_and_session}/\").extract(\"/{session}\")"
81+
}
82+
83+
aws {
84+
account_id = data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id
85+
}
86+
}
87+
88+
resource "google_service_account_iam_member" "controller_custom" {
89+
count = data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id != null ? 1 : 0
90+
91+
lifecycle {
92+
precondition {
93+
condition = (data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id != null && var.sysdig_account_id == null)
94+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
95+
}
96+
}
97+
98+
service_account_id = google_service_account.controller.name
99+
role = "roles/iam.workloadIdentityUser"
100+
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.agentless.name}/attribute.aws_account/${data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id}"
101+
}
102+
103+
resource "google_iam_workload_identity_pool_provider" "agentless_gcp" {
104+
count = var.sysdig_account_id != null ? 1 : 0
105+
106+
lifecycle {
107+
precondition {
108+
condition = (data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id == null && var.sysdig_account_id != null)
109+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
110+
}
111+
}
112+
113+
workload_identity_pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id
114+
workload_identity_pool_provider_id = "sysdig-ahs-${local.suffix}-gcp"
115+
display_name = "Sysdig Agentless Controller"
116+
description = "GCP identity pool provider for Sysdig Secure Agentless Host Scanning"
117+
disabled = false
118+
119+
attribute_condition = "google.subject == \"${var.sysdig_account_id}\""
120+
121+
attribute_mapping = {
122+
"google.subject" = "assertion.sub"
123+
"attribute.sa_id" = "assertion.sub"
124+
}
125+
126+
oidc {
127+
issuer_uri = "https://accounts.google.com"
128+
}
129+
}
130+
131+
resource "google_service_account_iam_member" "controller_custom_gcp" {
132+
count = var.sysdig_account_id != null ? 1 : 0
133+
134+
lifecycle {
135+
precondition {
136+
condition = (data.sysdig_secure_agentless_scanning_assets.assets.backend.cloud_id == null && var.sysdig_account_id != null)
137+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
138+
}
139+
}
140+
141+
service_account_id = google_service_account.controller.name
142+
role = "roles/iam.workloadIdentityUser"
143+
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.agentless.name}/attribute.sa_id/${var.sysdig_account_id}"
144+
}
145+
146+
#-----------------------------------------------------------------------------------------
147+
# Custom IAM roles and bindings
148+
#-----------------------------------------------------------------------------------------
149+
150+
resource "google_project_iam_custom_role" "controller" {
151+
count = var.is_organizational ? 0 : 1
152+
153+
project = var.project_id
154+
role_id = "${var.role_name}Discovery${local.suffix}"
155+
title = "${var.role_name}, for Host Discovery"
156+
permissions = local.host_discovery_permissions
157+
}
158+
159+
resource "google_project_iam_binding" "controller_custom" {
160+
count = var.is_organizational ? 0 : 1
161+
162+
project = var.project_id
163+
role = google_project_iam_custom_role.controller[0].id
164+
members = [
165+
"serviceAccount:${google_service_account.controller.email}",
166+
]
167+
}
168+
169+
resource "google_project_iam_custom_role" "worker_role" {
170+
count = var.is_organizational ? 0 : 1
171+
172+
project = var.project_id
173+
role_id = "${var.role_name}Scan${local.suffix}"
174+
title = "${var.role_name}, for Host Scan"
175+
permissions = local.host_scan_permissions
176+
}
177+
178+
resource "google_project_iam_binding" "admin_account_iam" {
179+
count = var.is_organizational ? 0 : 1
180+
181+
project = var.project_id
182+
role = google_project_iam_custom_role.worker_role[0].id
183+
members = [
184+
"serviceAccount:${data.sysdig_secure_agentless_scanning_assets.assets.gcp.worker_identity}",
185+
]
186+
}
187+
188+
#-----------------------------------------------------------------------------------------------------------------------------------------
189+
# Call Sysdig Backend to add the agentless-scan integration to the Sysdig Cloud Account
190+
#
191+
# Note (optional): To ensure this gets called after all cloud resources are created, add
192+
# explicit dependency using depends_on
193+
#-----------------------------------------------------------------------------------------------------------------------------------------
194+
195+
resource "sysdig_secure_cloud_auth_account_component" "gcp_agentless_scan" {
196+
account_id = var.sysdig_secure_account_id
197+
type = "COMPONENT_SERVICE_PRINCIPAL"
198+
instance = "secure-scanning"
199+
version = "v0.1.0"
200+
service_principal_metadata = jsonencode({
201+
gcp = {
202+
workload_identity_federation = {
203+
pool_provider_id = data.sysdig_secure_agentless_scanning_assets.assets.gcp.worker_identity != null ? google_iam_workload_identity_pool_provider.agentless[0].name : var.sysdig_account_id != null ? google_iam_workload_identity_pool_provider.agentless_gcp[0].name : null
204+
}
205+
email = google_service_account.controller.email
206+
}
207+
})
208+
}

0 commit comments

Comments
 (0)