From 6224133f5696ae438075c242ddd4d07ed8dc6c64 Mon Sep 17 00:00:00 2001 From: Mitul Sheth <97634367+mms2409@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:17:41 -0500 Subject: [PATCH] feat: agentless workload controller WIF (#20) --- AUTHORS | 1 + modules/services/workload-scan/controller.tf | 123 +++++++++++++++++++ modules/services/workload-scan/data.tf | 3 + modules/services/workload-scan/locals.tf | 8 ++ modules/services/workload-scan/outputs.tf | 32 +++++ modules/services/workload-scan/provider.tf | 14 +++ modules/services/workload-scan/variables.tf | 29 +++++ 7 files changed, 210 insertions(+) create mode 100644 modules/services/workload-scan/controller.tf create mode 100644 modules/services/workload-scan/data.tf create mode 100644 modules/services/workload-scan/locals.tf create mode 100644 modules/services/workload-scan/outputs.tf create mode 100644 modules/services/workload-scan/provider.tf create mode 100644 modules/services/workload-scan/variables.tf diff --git a/AUTHORS b/AUTHORS index bba378a..6767cbb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,5 +9,6 @@ Co-authored-by: Fede Barcelona Co-authored-by: Miguel Angel Baztán Co-authored-by: Rubén Eguiluz Co-authored-by: Iru +Co-authored-by: Mitul Sheth Co-authored-by: Hayk Kocharyan Co-authored-by: David González Diez diff --git a/modules/services/workload-scan/controller.tf b/modules/services/workload-scan/controller.tf new file mode 100644 index 0000000..bbc46bc --- /dev/null +++ b/modules/services/workload-scan/controller.tf @@ -0,0 +1,123 @@ +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", + + # workload identity federation + "iam.serviceAccounts.getAccessToken", + ] +} + +resource "google_project_iam_binding" "controller_custom" { + 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" { + count = var.sysdig_backend != null ? 1 : 0 + + lifecycle { + precondition { + condition = (var.sysdig_backend != null && var.sysdig_account_id == null) + error_message = "Cannot provide both sysdig_backend or sysdig_account_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_account==\"${var.sysdig_backend}\"" + + attribute_mapping = { + "google.subject" = "assertion.arn" + "attribute.aws_account" = "assertion.account" + "attribute.role" = "assertion.arn.extract(\"/assumed-role/{role}/\")" + "attribute.session" = "assertion.arn.extract(\"/assumed-role/{role_and_session}/\").extract(\"/{session}\")" + } + + aws { + account_id = var.sysdig_backend + } +} + +resource "google_service_account_iam_member" "controller_custom" { + count = var.sysdig_backend != null ? 1 : 0 + + lifecycle { + precondition { + condition = (var.sysdig_backend != null && var.sysdig_account_id == null) + error_message = "Cannot provide both sysdig_backend or sysdig_account_id" + } + } + + service_account_id = google_service_account.controller.name + role = "roles/iam.workloadIdentityUser" + member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.agentless.name}/attribute.aws_account/${var.sysdig_backend}" +} + +resource "google_iam_workload_identity_pool_provider" "agentless_gcp" { + count = var.sysdig_account_id != null ? 1 : 0 + + lifecycle { + precondition { + condition = (var.sysdig_backend == null && var.sysdig_account_id != null) + error_message = "Cannot provide both sysdig_backend or sysdig_account_id" + } + } + + workload_identity_pool_id = google_iam_workload_identity_pool.agentless.workload_identity_pool_id + workload_identity_pool_provider_id = "sysdig-ws-${local.suffix}-gcp" + display_name = "Sysdig Agentless Workload Controller" + description = "GCP identity pool provider for Sysdig Secure Agentless Workload Scanning" + disabled = false + + attribute_condition = "google.subject == \"${var.sysdig_account_id}\"" + + attribute_mapping = { + "google.subject" = "assertion.sub" + "attribute.sa_id" = "assertion.sub" + } + + oidc { + issuer_uri = "https://accounts.google.com" + } +} + +resource "google_service_account_iam_member" "controller_custom_gcp" { + count = var.sysdig_account_id != null ? 1 : 0 + + lifecycle { + precondition { + condition = (var.sysdig_backend == null && var.sysdig_account_id != null) + error_message = "Cannot provide both sysdig_backend or sysdig_account_id" + } + } + + service_account_id = google_service_account.controller.name + role = "roles/iam.workloadIdentityUser" + member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.agentless.name}/attribute.sa_id/${var.sysdig_account_id}" +} diff --git a/modules/services/workload-scan/data.tf b/modules/services/workload-scan/data.tf new file mode 100644 index 0000000..10117db --- /dev/null +++ b/modules/services/workload-scan/data.tf @@ -0,0 +1,3 @@ +data "google_project" "project" { + project_id = var.project_id +} diff --git a/modules/services/workload-scan/locals.tf b/modules/services/workload-scan/locals.tf new file mode 100644 index 0000000..d3ba27c --- /dev/null +++ b/modules/services/workload-scan/locals.tf @@ -0,0 +1,8 @@ +locals { + suffix = var.suffix == null ? random_id.suffix[0].hex : var.suffix +} + +resource "random_id" "suffix" { + count = var.suffix == null ? 1 : 0 + byte_length = 3 +} diff --git a/modules/services/workload-scan/outputs.tf b/modules/services/workload-scan/outputs.tf new file mode 100644 index 0000000..f2e10fa --- /dev/null +++ b/modules/services/workload-scan/outputs.tf @@ -0,0 +1,32 @@ +output "project_id" { + value = var.project_id +} + +output "project_number" { + value = data.google_project.project.number +} + +output "controller_service_account" { + value = google_service_account.controller.email +} + +output "workload_identity_pool_provider" { + 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 + precondition { + condition = (var.sysdig_backend != null && var.sysdig_account_id == null) || (var.sysdig_backend == null && var.sysdig_account_id != null) + error_message = "Cannot provide both sysdig_backend or sysdig_account_id" + } +} + +output "json_payload" { + value = jsonencode({ + "projectId" = var.project_id + "projectNumber" = data.google_project.project.number + "serviceAccount" = google_service_account.controller.email + "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 + }) + precondition { + condition = (var.sysdig_backend != null && var.sysdig_account_id == null) || (var.sysdig_backend == null && var.sysdig_account_id != null) + error_message = "Cannot provide both sysdig_backend or sysdig_account_id" + } +} diff --git a/modules/services/workload-scan/provider.tf b/modules/services/workload-scan/provider.tf new file mode 100644 index 0000000..fba49cf --- /dev/null +++ b/modules/services/workload-scan/provider.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">=1.0" + + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.1, < 5.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.1, < 4.0" + } + } +} \ No newline at end of file diff --git a/modules/services/workload-scan/variables.tf b/modules/services/workload-scan/variables.tf new file mode 100644 index 0000000..93100c3 --- /dev/null +++ b/modules/services/workload-scan/variables.tf @@ -0,0 +1,29 @@ +variable "project_id" { + type = string + description = "GCP Project ID" +} + +variable "sysdig_backend" { + type = string + description = "Sysdig provided AWS Account designated for the workload scan.
One of `sysdig_backend` or `sysdig_account_id`must be provided" + default = null +} + +variable "sysdig_account_id" { + type = string + description = "Sysdig provided GCP Account designated for the workload scan.
One of `sysdig_backend` or `sysdig_account_id`must be provided" + default = null +} + +# optionals +variable "role_name" { + type = string + description = "Name for the Worker Role on the Customer infrastructure" + default = "SysdigAgentlessWorkloadRole" +} + +variable "suffix" { + type = string + description = "By default a random value will be autogenerated.
Suffix word to enable multiple deployments with different naming
(Workload Identity Pool and Providers have a soft deletion on Google Platform that will disallow name re-utilization)" + default = null +}