diff --git a/modules/services/workload-scan/provider.tf b/modules/services/workload-scan/provider.tf index fba49cf..13561b5 100644 --- a/modules/services/workload-scan/provider.tf +++ b/modules/services/workload-scan/provider.tf @@ -10,5 +10,9 @@ terraform { source = "hashicorp/random" version = ">= 3.1, < 4.0" } + sysdig = { + source = "sysdiglabs/sysdig" + version = "~> 1.37" + } } } \ No newline at end of file diff --git a/modules/vm-workload-scanning/README.md b/modules/vm-workload-scanning/README.md new file mode 100644 index 0000000..d1ac2e1 --- /dev/null +++ b/modules/vm-workload-scanning/README.md @@ -0,0 +1,66 @@ +# GCP VM Workload Scanning Module + +This Module creates the resources required to perform agentless workload scanning operations in Google Cloud Platform (GCP). It sets up the necessary roles, service accounts, and workload identity providers to enable Sysdig to scan workloads running in GCP projects. + +By default, it will create a service account with permissions necessary to access and access GAR and GCR repositories and pull their images. + +The following resources will be created in each instrumented project: +- A Service Account and associated roles that allow Sysdig to perform tasks necessary for VM agentless workload scanning, i.e., access GAR/GCR repositories and pull its images. +- A Workload Identity Provider to facilitate secure authentication between GCP and Sysdig. + +### Requirements + +| Name | Version | +|------|---------| +| terraform | ~> 1.7 | +| google | >= 4.50.0 | +| sysdig | ~> 1.37 | + +### Providers + +| Name | Version | +|------|---------| +| google | >= 4.50.0 | +| sysdig | ~> 1.37 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| google_service_account.controller | resource | +| google_project_iam_member.controller | resource | +| google_iam_workload_identity_pool.agentless | resource | +| google_iam_workload_identity_pool_provider.agentless | resource | +| google_iam_workload_identity_pool.agentless_gcp | resource | +| google_iam_workload_identity_pool_provider.agentless_gcp | resource | +| google_project.project | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|----------------------------------------------------------------------------------------------------------------------------------|------|---------|:--------:| +| project_id | GCP Project ID | string | n/a | yes | +| is_organizational | Set this field to 'true' to deploy workload scanning to a GCP Organization. | bool | false | no | +| organization_domain | (Optional) Organization domain. e.g. sysdig.com | string | "" | no | +| role_name | Name for the Worker Role on the Customer infrastructure | string | "SysdigAgentlessWorkloadRole" | no | +| sysdig_secure_account_id | ID of the Sysdig Cloud Account to enable VM Workload Scanning for (in case of organization, ID of the Sysdig management account) | string | n/a | yes | + +### Outputs + +| Name | Description | +|------|-------------| +| vm_workload_scanning_component_id | Component identifier of service principal created in Sysdig Backend for VM Workload Scanning | + + + +## Authors + +Module is maintained by [Sysdig](https://sysdig.com). + +## License + +Apache 2 Licensed. See LICENSE for full details. diff --git a/modules/vm-workload-scanning/main.tf b/modules/vm-workload-scanning/main.tf new file mode 100644 index 0000000..fafefbb --- /dev/null +++ b/modules/vm-workload-scanning/main.tf @@ -0,0 +1,110 @@ +locals { + suffix = random_id.suffix.hex +} + +resource "random_id" "suffix" { + byte_length = 3 +} + +data "google_project" "project" { + project_id = var.project_id +} + +data "sysdig_secure_trusted_cloud_identity" "trusted_identity" { + cloud_provider = "gcp" +} + +data "sysdig_secure_tenant_external_id" "external_id" {} + +resource "google_service_account" "controller" { + project = var.project_id + account_id = "sysdig-ws-${local.suffix}" + display_name = "Sysdig Agentless Workload Scanning" +} + +resource "google_project_iam_custom_role" "controller" { + project = var.project_id + role_id = "${var.role_name}WorkloadController${title(local.suffix)}" + title = "Role for Sysdig Agentless Workload Controller" + permissions = [ + # artifact registry reader permissions + "artifactregistry.repositories.downloadArtifacts", + "artifactregistry.repositories.get", + "artifactregistry.repositories.list", + "artifactregistry.dockerimages.get", + "artifactregistry.dockerimages.list", + "storage.objects.get", + "storage.buckets.list", + "storage.objects.list", + + # workload identity federation + "iam.serviceAccounts.getAccessToken", + ] +} + +resource "google_project_iam_binding" "controller_binding" { + project = var.project_id + role = google_project_iam_custom_role.controller.id + + members = [ + "serviceAccount:${google_service_account.controller.email}", + ] +} + +resource "google_iam_workload_identity_pool" "agentless" { + workload_identity_pool_id = "sysdig-wl-${local.suffix}" +} + +resource "google_iam_workload_identity_pool_provider" "agentless" { + project = var.project_id + workload_identity_pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id + workload_identity_pool_provider_id = "sysdig-wl-${local.suffix}" + display_name = "Sysdig Workload Controller" + description = "AWS identity pool provider for Sysdig Secure Agentless Workload Scanning" + disabled = false + + attribute_condition = "attribute.aws_role==\"arn:aws:sts::${data.sysdig_secure_trusted_cloud_identity.trusted_identity.aws_account_id}:assumed-role/${data.sysdig_secure_trusted_cloud_identity.trusted_identity.aws_role_name}/${data.sysdig_secure_tenant_external_id.external_id.external_id}\"" + + attribute_mapping = { + "google.subject" = "assertion.arn", + "attribute.aws_role" = "assertion.arn" + } + + aws { + account_id = data.sysdig_secure_trusted_cloud_identity.trusted_identity.aws_account_id + } +} + +resource "google_service_account_iam_member" "controller_binding" { + service_account_id = google_service_account.controller.name + role = "roles/iam.workloadIdentityUser" + member = "principalSet://iam.googleapis.com/projects/${data.google_project.project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.agentless.workload_identity_pool_id}/attribute.aws_role/arn:aws:sts::${data.sysdig_secure_trusted_cloud_identity.trusted_identity.aws_account_id}:assumed-role/${data.sysdig_secure_trusted_cloud_identity.trusted_identity.aws_role_name}/${data.sysdig_secure_tenant_external_id.external_id.external_id}" +} + + +#-------------------------------------------------------------------------------------------------------------- +# Call Sysdig Backend to add the service-principal integration for VM Workload Scanning to the Sysdig Cloud Account +#-------------------------------------------------------------------------------------------------------------- +resource "sysdig_secure_cloud_auth_account_component" "google_service_principal" { + account_id = var.sysdig_secure_account_id + type = "COMPONENT_SERVICE_PRINCIPAL" + instance = "secure-vm-workload-scanning" + version = "v0.1.0" + service_principal_metadata = jsonencode({ + gcp = { + workload_identity_federation = { + pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id + pool_provider_id = google_iam_workload_identity_pool_provider.agentless.workload_identity_pool_provider_id + project_number = data.google_project.project.number + } + email = google_service_account.controller.email + } + }) + depends_on = [ + google_service_account.controller, + google_project_iam_custom_role.controller, + google_project_iam_binding.controller_binding, + google_iam_workload_identity_pool.agentless, + google_organization_iam_member.controller, + ] +} \ No newline at end of file diff --git a/modules/vm-workload-scanning/organizational.tf b/modules/vm-workload-scanning/organizational.tf new file mode 100644 index 0000000..8ecb725 --- /dev/null +++ b/modules/vm-workload-scanning/organizational.tf @@ -0,0 +1,35 @@ +#--------------# +# Organization # +#--------------# + +data "google_organization" "org" { + count = var.is_organizational ? 1 : 0 + domain = var.organization_domain +} + +################################################### +# Setup Service Account permissions +################################################### + +#--------------------------------------------------------------------------------------------- +# role permissions for CSPM (GCP Predefined Roles for Sysdig Cloud Secure Posture Management) +#--------------------------------------------------------------------------------------------- +resource "google_organization_iam_member" "controller" { + # adding ciem role with permissions to the service account alongside cspm roles + for_each = var.is_organizational ? toset([ + "artifactregistry.repositories.downloadArtifacts", + "artifactregistry.repositories.get", + "artifactregistry.repositories.list", + "artifactregistry.dockerimages.get", + "artifactregistry.dockerimages.list", + "storage.objects.get", + "storage.buckets.list", + "storage.objects.list", + + # workload identity federation + "iam.serviceAccounts.getAccessToken"]) : [] + + org_id = data.google_organization.org[0].org_id + role = each.key + member = "serviceAccount:${google_service_account.controller.email}" +} \ No newline at end of file diff --git a/modules/vm-workload-scanning/outputs.tf b/modules/vm-workload-scanning/outputs.tf new file mode 100644 index 0000000..fa9f16b --- /dev/null +++ b/modules/vm-workload-scanning/outputs.tf @@ -0,0 +1,5 @@ +output "vm_workload_scanning_component_id" { + value = "${sysdig_secure_cloud_auth_account_component.google_service_principal.type}/${sysdig_secure_cloud_auth_account_component.google_service_principal.instance}" + description = "Component identifier of service principal created in Sysdig Backend for VM Workload Scanning" + depends_on = [sysdig_secure_cloud_auth_account_component.google_service_principal] +} diff --git a/modules/vm-workload-scanning/variables.tf b/modules/vm-workload-scanning/variables.tf new file mode 100644 index 0000000..c904eec --- /dev/null +++ b/modules/vm-workload-scanning/variables.tf @@ -0,0 +1,28 @@ +variable "project_id" { + type = string + description = "GCP Project ID" +} + +variable "is_organizational" { + type = bool + description = "Set this field to 'true' to deploy workload scanning to a GCP Organization." + default = false +} + +variable "organization_domain" { + type = string + description = "(Optional) Organization domain. e.g. sysdig.com" + default = false +} + +# optionals +variable "role_name" { + type = string + description = "Name for the Worker Role on the Customer infrastructure" + default = "SysdigAgentlessWorkloadRole" +} + +variable "sysdig_secure_account_id" { + type = string + description = "ID of the Sysdig Cloud Account to enable Config Posture for (in case of organization, ID of the Sysdig management account)" +} diff --git a/modules/vm-workload-scanning/versions.tf b/modules/vm-workload-scanning/versions.tf new file mode 100644 index 0000000..c16110f --- /dev/null +++ b/modules/vm-workload-scanning/versions.tf @@ -0,0 +1,18 @@ +terraform { + required_version = ">=1.0" + + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.21.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.1, < 4.0" + } + sysdig = { + source = "sysdiglabs/sysdig" + version = "~> 1.37" + } + } +} \ No newline at end of file diff --git a/test/examples/modular_organization/vm-workload-scanning-cloud-run.tf b/test/examples/modular_organization/vm-workload-scanning-cloud-run.tf new file mode 100644 index 0000000..9506c3b --- /dev/null +++ b/test/examples/modular_organization/vm-workload-scanning-cloud-run.tf @@ -0,0 +1,17 @@ +module "vm_workload_scanning" { + source = "../../../modules/vm-workload-scanning" + + project_id = module.onboarding.project_id + is_organizational = module.onboarding.is_organizational + organization_domain = module.onboarding.organization_domain + sysdig_secure_account_id = module.onboarding.sysdig_secure_account_id +} + + +resource "sysdig_secure_cloud_auth_account_feature" "config_cloud_run" { + account_id = module.onboarding.sysdig_secure_account_id + type = "FEATURE_SECURE_WORKLOAD_SCANNING_CONTAINERS" + enabled = true + components = [module.vm_workload_scanning.vm_workload_scanning_component_id] + depends_on = [module.vm_workload_scanning] +} \ No newline at end of file diff --git a/test/examples/modular_organization/vm-workload-scanning-functions.tf b/test/examples/modular_organization/vm-workload-scanning-functions.tf new file mode 100644 index 0000000..f8a3489 --- /dev/null +++ b/test/examples/modular_organization/vm-workload-scanning-functions.tf @@ -0,0 +1,17 @@ +module "vm_workload_scanning" { + source = "../../../modules/vm-workload-scanning" + + project_id = module.onboarding.project_id + is_organizational = module.onboarding.is_organizational + organization_domain = module.onboarding.organization_domain + sysdig_secure_account_id = module.onboarding.sysdig_secure_account_id +} + + +resource "sysdig_secure_cloud_auth_account_feature" "config_functions" { + account_id = module.onboarding.sysdig_secure_account_id + type = "FEATURE_SECURE_WORKLOAD_SCANNING_FUNCTIONS" + enabled = true + components = [module.vm_workload_scanning.vm_workload_scanning_component_id] + depends_on = [module.vm_workload_scanning] +} \ No newline at end of file diff --git a/test/examples/modular_organization/vm-workload-scanning-gke.tf b/test/examples/modular_organization/vm-workload-scanning-gke.tf new file mode 100644 index 0000000..5ace0bb --- /dev/null +++ b/test/examples/modular_organization/vm-workload-scanning-gke.tf @@ -0,0 +1,17 @@ +module "vm_workload_scanning" { + source = "../../../modules/vm-workload-scanning" + + project_id = module.onboarding.project_id + is_organizational = module.onboarding.is_organizational + organization_domain = module.onboarding.organization_domain + sysdig_secure_account_id = module.onboarding.sysdig_secure_account_id +} + + +resource "sysdig_secure_cloud_auth_account_feature" "config_gke" { + account_id = module.onboarding.sysdig_secure_account_id + type = "FEATURE_SECURE_WORKLOAD_SCANNING_KUBERNETES" + enabled = true + components = [module.vm_workload_scanning.vm_workload_scanning_component_id] + depends_on = [module.vm_workload_scanning] +} \ No newline at end of file diff --git a/test/examples/modular_single_project/vm-workload-scanning-cloud-run.tf b/test/examples/modular_single_project/vm-workload-scanning-cloud-run.tf new file mode 100644 index 0000000..7763f4c --- /dev/null +++ b/test/examples/modular_single_project/vm-workload-scanning-cloud-run.tf @@ -0,0 +1,15 @@ +module "vm_workload_scanning" { + source = "../../../modules/vm-workload-scanning" + + project_id = module.onboarding.project_id + sysdig_secure_account_id = module.onboarding.sysdig_secure_account_id +} + + +resource "sysdig_secure_cloud_auth_account_feature" "config_cloud_run" { + account_id = module.onboarding.sysdig_secure_account_id + type = "FEATURE_SECURE_WORKLOAD_SCANNING_CONTAINERS" + enabled = true + components = [module.vm_workload_scanning.vm_workload_scanning_component_id] + depends_on = [module.vm_workload_scanning] +} \ No newline at end of file diff --git a/test/examples/modular_single_project/vm-workload-scanning-functions.tf b/test/examples/modular_single_project/vm-workload-scanning-functions.tf new file mode 100644 index 0000000..3191eeb --- /dev/null +++ b/test/examples/modular_single_project/vm-workload-scanning-functions.tf @@ -0,0 +1,15 @@ +module "vm_workload_scanning" { + source = "../../../modules/vm-workload-scanning" + + project_id = module.onboarding.project_id + sysdig_secure_account_id = module.onboarding.sysdig_secure_account_id +} + + +resource "sysdig_secure_cloud_auth_account_feature" "config_functions" { + account_id = module.onboarding.sysdig_secure_account_id + type = "FEATURE_SECURE_WORKLOAD_SCANNING_FUNCTIONS" + enabled = true + components = [module.vm_workload_scanning.vm_workload_scanning_component_id] + depends_on = [module.vm_workload_scanning] +} \ No newline at end of file diff --git a/test/examples/modular_single_project/vm-workload-scanning-gke.tf b/test/examples/modular_single_project/vm-workload-scanning-gke.tf new file mode 100644 index 0000000..fea16c4 --- /dev/null +++ b/test/examples/modular_single_project/vm-workload-scanning-gke.tf @@ -0,0 +1,15 @@ +module "vm_workload_scanning" { + source = "../../../modules/vm-workload-scanning" + + project_id = module.onboarding.project_id + sysdig_secure_account_id = module.onboarding.sysdig_secure_account_id +} + + +resource "sysdig_secure_cloud_auth_account_feature" "config_gke" { + account_id = module.onboarding.sysdig_secure_account_id + type = "FEATURE_SECURE_WORKLOAD_SCANNING_KUBERNETES" + enabled = true + components = [module.vm_workload_scanning.vm_workload_scanning_component_id] + depends_on = [module.vm_workload_scanning] +} \ No newline at end of file