Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for WIF based auth to Webhook Datasource module #21

Merged
merged 7 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions modules/services/webhook-datasource/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ The following resources will be created in each instrumented account:
- A `PubSub` ingestion topic that will hold all the AuditLogs coming from the specified project
- A `Push` Subscription that will POST the AuditLogs collected from the project towards Sysdig's backend
- All the necessary `Service Accounts` and `Policies` to enable the `AuditLogs` publishing operation
- A `Workload Identity Pool`, `Provider` and added custom role permissions to the `Service Account`, to allow Sysdig to authenticate to GCP on your behalf to validate resources.

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
| <a name="requirement_google"></a> [google](#requirement\_google) | >= 4.21.0 |
| <a name="requirement_sysdig"></a> [sysdig](#requirement\_sysdig) | >= 1.19.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_google"></a> [google](#provider\_google) | 5.0.0 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 3.1 |

## Modules

Expand All @@ -41,6 +44,16 @@ No modules.
| [google_service_account.push_auth](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource |
| [google_service_account_iam_binding.push_auth_binding](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_binding) | resource |
| [google_organization.org](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/organization) | data source |
| [sysdig_secure_trusted_cloud_identity.trusted_identity](https://registry.terraform.io/providers/sysdiglabs/sysdig/latest/docs/data-sources/secure_trusted_cloud_identity) | data source |
| [google_project.project](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/project) | data source |
| [random_id.suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [google_iam_workload_identity_pool.ingestion_auth_pool](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool) | resource |
| [google_iam_workload_identity_pool_provider.ingestion_auth_pool_provider](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider) | resource |
| [google_project_iam_custom_role.custom_ingestion_auth_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam_custom_role) | resource |
| [google_project_iam_member.custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam#google_project_iam_member) | resource |
| [google_service_account_iam_member.custom_auth](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_service_account_iam#google_service_account_iam_member) | resource |
| [google_organization_iam_custom_role.custom_ingestion_auth_role](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_organization_iam_custom_role) | resource |
| [google_organization_iam_member.custom](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_organization_iam#google_organization_iam_member) | resource |

## Inputs

Expand All @@ -56,6 +69,9 @@ No modules.
| <a name="input_organization_domain"></a> [organization\_domain](#input\_organization\_domain) | Organization domain. e.g. sysdig.com | `string` | `""` | no |
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | (Required) Target Project identifier provided by the customer | `string` | n/a | yes |
| <a name="input_push_endpoint"></a> [push\_endpoint](#input\_push\_endpoint) | (Required) Final endpoint towards which audit logs POST calls will be directed | `string` | n/a | yes |
| <a name="input_role_name"></a> [role\_name](#input\_role\_name) | (Optional) Role name for custom role binding to the service account, with read permissions for data ingestion resources | `string` | `"SysdigIngestionAuthRole"` | no |
| <a name="input_external_id"></a> [external\_id](#input\_external\_id) | (Optional) Random string generated unique to a customer | `string` | `""` | no |
| <a name="input_suffix"></a> [suffix](#input\_suffix) | (Optional) Suffix to uniquely identify resources during multiple installs. If not provided, random value is autogenerated | `string` | `null` | no |

## Outputs

Expand All @@ -65,3 +81,7 @@ No modules.
| <a name="output_ingestion_pubsub_topic_name"></a> [ingestion\_pubsub\_topic\_name](#output\_ingestion\_pubsub\_topic\_name) | PubSub ingestion topic that will hold all the AuditLogs coming from the specified project |
| <a name="output_ingestion_sink_name"></a> [ingestion\_sink\_name](#output\_ingestion\_sink\_name) | Project/Organization sink to direct the AuditLogs towards a dedicated PubSub topic |
| <a name="output_ingestion_push_subscription_name"></a> [ingestion\_push\_subscription\_name](#output\_ingestion\_push\_subscription\_name) | Push Subscription that will POST the AuditLogs collected from the project towards Sysdig's backend |
| <a name="output_workload_identity_pool_id"></a> [workload\_identity\_pool\_id](#output\_workload\_identity\_pool\_id) | Id of Workload Identity Pool for authenticating to GCP to access data ingestion resources |
| <a name="output_workload_identity_pool_provider_id"></a> [workload\_identity\_pool\_provider\_id](#output\_workload\_identity\_pool\_provider\_id) | Id of Workload Identity Pool Provider for authenticating to GCP to access data ingestion resources |
| <a name="output_workload_identity_project_number"></a> [workload\_identity\_project\_number](#output\_workload\_identity\_project\_number) | GCP project number |
| <a name="output_service_account_email"></a> [service\_account\_email](#output\_service\_account\_email) | email of the Service Account created |
85 changes: 85 additions & 0 deletions modules/services/webhook-datasource/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,88 @@ resource "google_pubsub_subscription" "ingestion_topic_push_subscription" {
}
}

#------------------------------------------------------------------#
# Fetch and compute required data for Workload Identity Federation #
#------------------------------------------------------------------#

data "sysdig_secure_trusted_cloud_identity" "trusted_identity" {
cloud_provider = "gcp"
}

data "google_project" "project" {
project_id = var.project_id
}

locals {
suffix = var.suffix == null ? random_id.suffix[0].hex : var.suffix
}

// suffix to uniquely identify WIF pool and provider during multiple installs. If suffix value is not provided, this will generate a random value.
resource "random_id" "suffix" {
ravinadhruve10 marked this conversation as resolved.
Show resolved Hide resolved
count = var.suffix == null ? 1 : 0
byte_length = 3
}

#------------------------------------------------------------#
# Configure Workload Identity Federation for auth #
# See https://cloud.google.com/iam/docs/access-resources-aws #
#------------------------------------------------------------#

resource "google_iam_workload_identity_pool" "ingestion_auth_pool" {
project = var.project_id
workload_identity_pool_id = "sysdig-ingestion-${local.suffix}"
}

resource "google_iam_workload_identity_pool_provider" "ingestion_auth_pool_provider" {
project = var.project_id
workload_identity_pool_id = google_iam_workload_identity_pool.ingestion_auth_pool.workload_identity_pool_id
workload_identity_pool_provider_id = "sysdig-ingestion-${local.suffix}"
display_name = "Sysdigcloud ingestion auth"
description = "AWS identity pool provider for Sysdig Secure Data Ingestion resources"
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}/${var.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
}
}

# creating custom role with project-level permissions to access data ingestion resources
resource "google_project_iam_custom_role" "custom_ingestion_auth_role" {
count = var.is_organizational ? 0 : 1

project = var.project_id
role_id = var.role_name
title = "Sysdigcloud Ingestion Auth Role"
description = "A Role providing the required permissions for Sysdig Backend to read cloud resources created for data ingestion"
permissions = [
"pubsub.topics.get",
"pubsub.topics.list",
"pubsub.subscriptions.get",
"pubsub.subscriptions.list",
"logging.sinks.get",
"logging.sinks.list",
]
}

# adding custom role with project-level permissions to the service account for auth
resource "google_project_iam_member" "custom" {
count = var.is_organizational ? 0 : 1

project = var.project_id
role = google_project_iam_custom_role.custom_ingestion_auth_role[0].id
member = "serviceAccount:${google_service_account.push_auth.email}"
}

# attaching WIF as a member to the service account for auth
resource "google_service_account_iam_member" "custom_auth" {
service_account_id = google_service_account.push_auth.name
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/projects/${data.google_project.project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.ingestion_auth_pool.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}/${var.external_id}"
}
27 changes: 27 additions & 0 deletions modules/services/webhook-datasource/organizational.tf
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,30 @@ resource "google_logging_organization_sink" "ingestion_sink" {
# even from potential sub-organizations
include_children = true
}

# creating custom role with organization-level permissions to access data ingestion resources
resource "google_organization_iam_custom_role" "custom_ingestion_auth_role" {
count = var.is_organizational ? 1 : 0

org_id = data.google_organization.org[0].org_id
role_id = var.role_name
title = "Sysdigcloud Ingestion Auth Role"
description = "A Role providing the required permissions for Sysdig Backend to read cloud resources created for data ingestion"
permissions = [
"pubsub.topics.get",
"pubsub.topics.list",
"pubsub.subscriptions.get",
"pubsub.subscriptions.list",
"logging.sinks.get",
"logging.sinks.list",
]
}

# adding custom role with organization-level permissions to the service account for auth
resource "google_organization_iam_member" "custom" {
count = var.is_organizational ? 1 : 0

org_id = data.google_organization.org[0].org_id
role = google_organization_iam_custom_role.custom_ingestion_auth_role[0].id
member = "serviceAccount:${google_service_account.push_auth.email}"
}
20 changes: 20 additions & 0 deletions modules/services/webhook-datasource/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,23 @@ output "ingestion_push_subscription_name" {
value = google_pubsub_subscription.ingestion_topic_push_subscription.name
description = "Push Subscription that will POST the AuditLogs collected from the project towards Sysdig's backend"
}

ravinadhruve10 marked this conversation as resolved.
Show resolved Hide resolved
output "workload_identity_pool_id" {
value = google_iam_workload_identity_pool.ingestion_auth_pool.workload_identity_pool_id
description = "Id of Workload Identity Pool for authenticating to GCP to access data ingestion resources"
}

output "workload_identity_pool_provider_id" {
value = google_iam_workload_identity_pool_provider.ingestion_auth_pool_provider.workload_identity_pool_provider_id
description = "Id of Workload Identity Pool Provider for authenticating to GCP to access data ingestion resources"
}

output "workload_identity_project_number" {
value = data.google_project.project.number
description = "GCP project number"
}

output "service_account_email" {
value = google_service_account.push_auth.email
description = "email of the Service Account created"
}
18 changes: 18 additions & 0 deletions modules/services/webhook-datasource/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,21 @@ variable "organization_domain" {
description = "(Optional) Organization domain. e.g. sysdig.com"
default = ""
}

variable "role_name" {
type = string
description = "Name for the Ingestion auth Role on the Customer infrastructure"
default = "SysdigIngestionAuthRole"
}

variable "external_id" {
ravinadhruve10 marked this conversation as resolved.
Show resolved Hide resolved
type = string
description = "Random string generated unique to a customer"
default = ""
}

variable "suffix" {
type = string
description = "Suffix to uniquely identify resources during multiple installs. If not provided, random value is autogenerated"
default = null
}
8 changes: 8 additions & 0 deletions modules/services/webhook-datasource/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,13 @@ terraform {
source = "hashicorp/google"
version = ">= 4.21.0"
}
sysdig = {
source = "sysdiglabs/sysdig"
version = "~> 1.19.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.1, < 4.0"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ terraform {
required_providers {
sysdig = {
source = "sysdiglabs/sysdig"
version = "~> 1.18.2"
version = "~> 1.19.0"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ terraform {
required_providers {
sysdig = {
source = "sysdiglabs/sysdig"
version = "~> 1.18.2"
version = "~> 1.19.0"
}
}
}
Expand Down
29 changes: 27 additions & 2 deletions test/examples/secure_threat_detection/organization/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module "organization-threat-detection" {
push_endpoint = "test_sysdig_secure_cloudingestion_endpoint"
is_organizational = true
organization_domain = "mytestorg.com"
external_id = "external_id"
}

module "organization-posture" {
Expand All @@ -24,7 +25,7 @@ terraform {
required_providers {
sysdig = {
source = "sysdiglabs/sysdig"
version = "~> 1.18.2"
version = "~> 1.19.0"
}
}
}
Expand All @@ -43,12 +44,36 @@ resource "sysdig_secure_cloud_auth_account" "gcp_project_mytestproject" {

secure_threat_detection {
enabled = true
components = ["COMPONENT_WEBHOOK_DATASOURCE/secure-runtime"]
components = ["COMPONENT_WEBHOOK_DATASOURCE/secure-runtime", "COMPONENT_SERVICE_PRINCIPAL/secure-runtime"]
}
}
component {
type = "COMPONENT_WEBHOOK_DATASOURCE"
instance = "secure-runtime"
webhook_datasource_metadata = jsonencode({
gcp = {
webhook_datasource = {
pubsub_topic_name = module.organization-threat-detection.ingestion_pubsub_topic_name
sink_name = module.organization-threat-detection.ingestion_sink_name
push_subscription_name = module.organization-threat-detection.ingestion_push_subscription_name
push_endpoint = module.organization-threat-detection.push_endpoint
}
}
})
}
component {
type = "COMPONENT_SERVICE_PRINCIPAL"
instance = "secure-runtime"
service_principal_metadata = jsonencode({
gcp = {
workload_identity_federation = {
pool_id = module.organization-threat-detection.workload_identity_pool_id
pool_provider_id = module.organization-threat-detection.workload_identity_pool_provider_id
project_number = module.organization-threat-detection.workload_identity_project_number
}
email = module.organization-threat-detection.service_account_email
}
})
}
component {
type = "COMPONENT_SERVICE_PRINCIPAL"
Expand Down
29 changes: 27 additions & 2 deletions test/examples/secure_threat_detection/single/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ module "single-project-threat-detection" {
source = "../../../..//modules/services/webhook-datasource"
project_id = "mytestproject"
push_endpoint = "test_sysdig_secure_cloudingestion_endpoint"
external_id = "external_id"
}

terraform {

required_providers {
sysdig = {
source = "sysdiglabs/sysdig"
version = "~> 1.18.2"
version = "~> 1.19.0"
}
}
}
Expand All @@ -33,12 +34,36 @@ resource "sysdig_secure_cloud_auth_account" "gcp_project_mytestproject" {

secure_threat_detection {
enabled = true
components = ["COMPONENT_WEBHOOK_DATASOURCE/secure-runtime"]
components = ["COMPONENT_WEBHOOK_DATASOURCE/secure-runtime", "COMPONENT_SERVICE_PRINCIPAL/secure-runtime"]
}
}
component {
type = "COMPONENT_WEBHOOK_DATASOURCE"
instance = "secure-runtime"
webhook_datasource_metadata = jsonencode({
gcp = {
webhook_datasource = {
pubsub_topic_name = module.single-project-threat-detection.ingestion_pubsub_topic_name
sink_name = module.single-project-threat-detection.ingestion_sink_name
push_subscription_name = module.single-project-threat-detection.ingestion_push_subscription_name
push_endpoint = module.single-project-threat-detection.push_endpoint
}
}
})
}
component {
type = "COMPONENT_SERVICE_PRINCIPAL"
instance = "secure-runtime"
service_principal_metadata = jsonencode({
gcp = {
workload_identity_federation = {
pool_id = module.single-project-threat-detection.workload_identity_pool_id
pool_provider_id = module.single-project-threat-detection.workload_identity_pool_provider_id
project_number = module.single-project-threat-detection. workload_identity_project_number
}
email = module.single-project-threat-detection.service_account_email
}
})
}
}

Loading