Skip to content

Commit a982d1d

Browse files
author
iru
authored
feat: agentless host scanner [SSPROD-33067] (#14)
* feat(cloudhostscanner): enables module * fix: * doc: generate terraform-docs * doc: update readme * doc: update readme
1 parent 1add598 commit a982d1d

File tree

9 files changed

+333
-0
lines changed

9 files changed

+333
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# GCP Agentless Scanning Module
2+
3+
4+
5+
6+
This module will deploy required resources for Sysdig to be able to scan hosts on your Google Cloud Account.
7+
8+
9+
The following resources will be created on 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+
![permission-diagram.png](permission-diagram.png)
16+
17+
Organizational support will be added later on.
18+
19+
<br/><br/>
20+
21+
## Usage
22+
23+
For usage instructions refer to Sysdig official documentation.
24+
While on Controlled Availability check with your Sysdig representative.
25+
<br/><br/>
26+
27+
<!-- BEGIN_TF_DOCS -->
28+
## Requirements
29+
30+
| Name | Version |
31+
|------|---------|
32+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >=1.0 |
33+
| <a name="requirement_google"></a> [google](#requirement\_google) | >= 4.1, < 5.0 |
34+
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.1, < 4.0 |
35+
36+
## Providers
37+
38+
| Name | Version |
39+
|------|---------|
40+
| <a name="provider_google"></a> [google](#provider\_google) | >= 4.1, < 5.0 |
41+
| <a name="provider_random"></a> [random](#provider\_random) | >= 3.1, < 4.0 |
42+
43+
## Modules
44+
45+
No modules.
46+
47+
## Resources
48+
49+
| Name | Type |
50+
|------|------|
51+
| [google_iam_workload_identity_pool.agentless](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool) | resource |
52+
| [google_iam_workload_identity_pool_provider.agentless](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider) | resource |
53+
| [google_iam_workload_identity_pool_provider.agentless_gcp](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider) | resource |
54+
| [google_project_iam_binding.admin-account-iam](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_binding) | resource |
55+
| [google_project_iam_binding.controller_custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_binding) | resource |
56+
| [google_project_iam_custom_role.controller](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_custom_role) | resource |
57+
| [google_project_iam_custom_role.worker_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_custom_role) | resource |
58+
| [google_service_account.controller](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource |
59+
| [google_service_account_iam_member.controller_custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_member) | resource |
60+
| [google_service_account_iam_member.controller_custom_gcp](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_member) | resource |
61+
| [random_id.suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
62+
| [google_project.project](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/project) | data source |
63+
64+
## Inputs
65+
66+
| Name | Description | Type | Default | Required |
67+
|------|-------------|------|---------|:--------:|
68+
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | GCP Project ID | `string` | n/a | yes |
69+
| <a name="input_worker_identity"></a> [worker\_identity](#input\_worker\_identity) | Sysdig provided Identity for the Service Account in charge of performing the host disk analysis | `string` | n/a | yes |
70+
| <a name="input_role_name"></a> [role\_name](#input\_role\_name) | Name for the Worker Role on the Customer infrastructure | `string` | `"SysdigAgentlessHostRole"` | no |
71+
| <a name="input_suffix"></a> [suffix](#input\_suffix) | By default a random value will be autogenerated.<br/>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) | `string` | `null` | no |
72+
| <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 |
73+
| <a name="input_sysdig_backend"></a> [sysdig\_backend](#input\_sysdig\_backend) | Sysdig provided AWS Account designated for the host scan.<br/>One of `sysdig_backend` or `sysdig_account_id`must be provided | `string` | `null` | no |
74+
75+
## Outputs
76+
77+
| Name | Description |
78+
|------|-------------|
79+
| <a name="output_controller_service_account"></a> [controller\_service\_account](#output\_controller\_service\_account) | n/a |
80+
| <a name="output_json_payload"></a> [json\_payload](#output\_json\_payload) | n/a |
81+
| <a name="output_project_id"></a> [project\_id](#output\_project\_id) | n/a |
82+
| <a name="output_project_number"></a> [project\_number](#output\_project\_number) | n/a |
83+
| <a name="output_workload_identity_pool_provider"></a> [workload\_identity\_pool\_provider](#output\_workload\_identity\_pool\_provider) | n/a |
84+
<!-- END_TF_DOCS -->
85+
86+
## Authors
87+
88+
Module is maintained by [Sysdig](https://sysdig.com).
89+
90+
## License
91+
92+
Apache 2 Licensed. See LICENSE for full details.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
resource "google_service_account" "controller" {
2+
project = var.project_id
3+
account_id = "sysdig-ahs-${local.suffix}"
4+
display_name = "Sysdig Agentless Host Scanning"
5+
}
6+
7+
resource "google_project_iam_custom_role" "controller" {
8+
project = var.project_id
9+
role_id = "${var.role_name}Controller${title(local.suffix)}"
10+
title = "Role for Sysdig Agentless Host Workers"
11+
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+
}
25+
26+
resource "google_project_iam_binding" "controller_custom" {
27+
project = var.project_id
28+
role = google_project_iam_custom_role.controller.id
29+
30+
members = [
31+
"serviceAccount:${google_service_account.controller.email}",
32+
]
33+
}
34+
35+
resource "google_iam_workload_identity_pool" "agentless" {
36+
workload_identity_pool_id = "sysdig-ahs-${local.suffix}"
37+
}
38+
39+
resource "google_iam_workload_identity_pool_provider" "agentless" {
40+
count = var.sysdig_backend != null ? 1 : 0
41+
42+
lifecycle {
43+
precondition {
44+
condition = (var.sysdig_backend != null && var.sysdig_account_id == null)
45+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
46+
}
47+
}
48+
49+
workload_identity_pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id
50+
workload_identity_pool_provider_id = "sysdig-ahs-${local.suffix}"
51+
display_name = "Sysdig Agentless Controller"
52+
description = "AWS identity pool provider for Sysdig Secure Agentless Host Scanning"
53+
disabled = false
54+
55+
attribute_condition = "attribute.aws_account==\"${var.sysdig_backend}\""
56+
57+
attribute_mapping = {
58+
"google.subject" = "assertion.arn"
59+
"attribute.aws_account" = "assertion.account"
60+
"attribute.role" = "assertion.arn.extract(\"/assumed-role/{role}/\")"
61+
"attribute.session" = "assertion.arn.extract(\"/assumed-role/{role_and_session}/\").extract(\"/{session}\")"
62+
}
63+
64+
aws {
65+
account_id = var.sysdig_backend
66+
}
67+
}
68+
69+
resource "google_service_account_iam_member" "controller_custom" {
70+
count = var.sysdig_backend != null ? 1 : 0
71+
72+
lifecycle {
73+
precondition {
74+
condition = (var.sysdig_backend != null && var.sysdig_account_id == null)
75+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
76+
}
77+
}
78+
79+
service_account_id = google_service_account.controller.name
80+
role = "roles/iam.workloadIdentityUser"
81+
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.agentless.name}/attribute.aws_account/${var.sysdig_backend}"
82+
}
83+
84+
resource "google_iam_workload_identity_pool_provider" "agentless_gcp" {
85+
count = var.sysdig_account_id != null ? 1 : 0
86+
87+
lifecycle {
88+
precondition {
89+
condition = (var.sysdig_backend == null && var.sysdig_account_id != null)
90+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
91+
}
92+
}
93+
94+
workload_identity_pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id
95+
workload_identity_pool_provider_id = "sysdig-ahs-${local.suffix}-gcp"
96+
display_name = "Sysdig Agentless Controller"
97+
description = "GCP identity pool provider for Sysdig Secure Agentless Host Scanning"
98+
disabled = false
99+
100+
attribute_condition = "google.subject == \"${var.sysdig_account_id}\""
101+
102+
attribute_mapping = {
103+
"google.subject" = "assertion.sub"
104+
"attribute.sa_id" = "assertion.sub"
105+
}
106+
107+
oidc {
108+
issuer_uri = "https://accounts.google.com"
109+
}
110+
}
111+
112+
resource "google_service_account_iam_member" "controller_custom_gcp" {
113+
count = var.sysdig_account_id != null ? 1 : 0
114+
115+
lifecycle {
116+
precondition {
117+
condition = (var.sysdig_backend == null && var.sysdig_account_id != null)
118+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
119+
}
120+
}
121+
122+
service_account_id = google_service_account.controller.name
123+
role = "roles/iam.workloadIdentityUser"
124+
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.agentless.name}/attribute.sa_id/${var.sysdig_account_id}"
125+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data "google_project" "project" {
2+
project_id = var.project_id
3+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
locals {
2+
suffix = var.suffix == null ? random_id.suffix[0].hex : var.suffix
3+
}
4+
5+
6+
resource "random_id" "suffix" {
7+
count = var.suffix == null ? 1 : 0
8+
byte_length = 3
9+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
output "project_id" {
2+
value = var.project_id
3+
}
4+
5+
output "project_number" {
6+
value = data.google_project.project.number
7+
}
8+
9+
output "controller_service_account" {
10+
value = google_service_account.controller.email
11+
}
12+
13+
output "workload_identity_pool_provider" {
14+
value = var.sysdig_backend != 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
15+
precondition {
16+
condition = (var.sysdig_backend != null && var.sysdig_account_id == null) || (var.sysdig_backend == null && var.sysdig_account_id != null)
17+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
18+
}
19+
}
20+
21+
output "json_payload" {
22+
value = jsonencode({
23+
"projectId" = var.project_id
24+
"projectNumber" = data.google_project.project.number
25+
"serviceAccount" = google_service_account.controller.email
26+
"identityProvider" = var.sysdig_backend != 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
27+
})
28+
precondition {
29+
condition = (var.sysdig_backend != null && var.sysdig_account_id == null) || (var.sysdig_backend == null && var.sysdig_account_id != null)
30+
error_message = "Cannot provide both sysdig_backend or sysdig_account_id"
31+
}
32+
}
121 KB
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
terraform {
2+
required_version = ">=1.0"
3+
4+
required_providers {
5+
google = {
6+
source = "hashicorp/google"
7+
version = ">= 4.1, < 5.0"
8+
}
9+
random = {
10+
source = "hashicorp/random"
11+
version = ">= 3.1, < 4.0"
12+
}
13+
}
14+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
variable "project_id" {
2+
type = string
3+
description = "GCP Project ID"
4+
}
5+
6+
variable "worker_identity" {
7+
type = string
8+
description = "Sysdig provided Identity for the Service Account in charge of performing the host disk analysis"
9+
}
10+
11+
variable "sysdig_backend" {
12+
type = string
13+
description = "Sysdig provided AWS Account designated for the host scan.<br/>One of `sysdig_backend` or `sysdig_account_id`must be provided"
14+
default = null
15+
}
16+
17+
variable "sysdig_account_id" {
18+
type = string
19+
description = "Sysdig provided GCP Account designated for the host scan.<br/>One of `sysdig_backend` or `sysdig_account_id`must be provided"
20+
default = null
21+
}
22+
23+
24+
# optionals
25+
variable "role_name" {
26+
type = string
27+
description = "Name for the Worker Role on the Customer infrastructure"
28+
default = "SysdigAgentlessHostRole"
29+
}
30+
31+
32+
33+
variable "suffix" {
34+
type = string
35+
description = "By default a random value will be autogenerated.<br/>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)"
36+
default = null
37+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
resource "google_project_iam_custom_role" "worker_role" {
2+
project = var.project_id
3+
role_id = "${var.role_name}Worker${title(local.suffix)}"
4+
title = "${var.role_name} - Sysdig Agentless"
5+
permissions = [
6+
# general stuff
7+
"compute.zoneOperations.get",
8+
# disks
9+
"compute.disks.get",
10+
"compute.disks.useReadOnly",
11+
]
12+
}
13+
14+
resource "google_project_iam_binding" "admin-account-iam" {
15+
project = var.project_id
16+
role = google_project_iam_custom_role.worker_role.id
17+
18+
members = [
19+
"serviceAccount:${var.worker_identity}",
20+
]
21+
}

0 commit comments

Comments
 (0)