Skip to content

Commit

Permalink
feat: GCP promote and quarantine add support for cross project
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-c-lee committed Mar 26, 2024
1 parent c3d48db commit 795fbe3
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
main.auto.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,19 @@ deployment_name = "<DEPLOYMENT_NAME>" // e.g. test-deployment

scan_result_topic = "<TOPIC_NAME>" // e.g. my-deployment-scan-result-topic
scanning_bucket = "<SCANNING_BUCKET_NAME>" // e.g. scanning-gcs-bucket
quarantine_mode = "move" // move or copy leave it empty

// quarantine settings
quarantine_mode = "move" // move or copy. default is move.
quarantine_bucket = "<QUARANTINE_BUCKET_NAME>" // e.g. quarantine-gcs-bucket Leave it empty if you don't want to quarantine files.
promote_mode = "move" // move or copy
quarantine_bucket_properties = { // additional properties for the quarantine bucket used when cross project or cross region is needed.
region = "<QUARANTINE_BUCKET_GCP_REGION>" // e.g. us-central1
project_id = "<QUARANTINE_BUCKET_GCP_PROJECT_ID>" // e.g. test-project-998877
}

// promote settings
promote_mode = "move" // move or copy. default is move.
promote_bucket = "<PROMOTE_BUCKET_NAME>" // e.g. promote-gcs-bucket Leave it empty if you don't want to promote files.
promote_bucket_properties = { // additional properties for the promote bucket used when cross project or cross region is needed.
region = "<PROMOTE_BUCKET_GCP_REGION>" // e.g. us-central1
project_id = "<PROMOTE_BUCKET_GCP_PROJECT>" // e.g. test-project-998877
}
111 changes: 55 additions & 56 deletions post-scan-actions/gcp-python-promote-or-quarantine/main.tf
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.11.0"
}
}
}

provider "google" {
project = var.project_id
region = var.region
locals {
promote_enabled = var.promote_bucket != ""
quarantine_enabled = var.quarantine_bucket != ""
}

resource "random_id" "deploy_suffix" {
Expand All @@ -28,61 +19,69 @@ data "archive_file" "source" {
}

resource "google_service_account" "service_account" {
account_id = "qua-pro-plugin-sa-${lower(random_id.deploy_suffix.hex)}"
display_name = "Quarantine/Promote plugin Service Account ${random_id.deploy_suffix.hex}"
project = var.project_id
account_id = "qua-pro-plugin-sa-${lower(random_id.deploy_suffix.hex)}"
display_name = "TM FSS Quarantine/Promote plugin Service Account ${random_id.deploy_suffix.hex}"
project = var.project_id
}

resource "google_project_iam_custom_role" "promote_and_quarantine_bucket_role" {
role_id = "plugin_storage_bucket_write_${lower(random_id.deploy_suffix.hex)}"
title = "Promote/Quarantine Bucket Write ${random_id.deploy_suffix.hex}"
resource "google_project_iam_custom_role" "promote_bucket_role" {
count = local.promote_enabled ? 1 : 0
role_id = "promote_bucket_write_${lower(random_id.deploy_suffix.hex)}"
title = "Promote Bucket Write ${random_id.deploy_suffix.hex}"
permissions = [
"storage.objects.create",
"storage.objects.delete",
"storage.objects.update"
]
provider = google.promote_provider
}

resource "google_project_iam_custom_role" "quarantine_bucket_role" {
count = local.quarantine_enabled ? 1 : 0
role_id = "quarantine_bucket_write_${lower(random_id.deploy_suffix.hex)}"
title = "Quarantine Bucket Write ${random_id.deploy_suffix.hex}"
permissions = [
"storage.objects.create",
"storage.objects.delete",
"storage.objects.update"
]
provider = google.quarantine_provider
}

resource "google_project_iam_custom_role" "scanning_bucket_access_role" {
role_id = "plugin_storage_bucket_access_${lower(random_id.deploy_suffix.hex)}"
title = "Scanning Bucket Access ${random_id.deploy_suffix.hex}"
title = "Scanning Bucket Access ${random_id.deploy_suffix.hex}"
permissions = var.promote_mode == "move" || var.quarantine_mode == "move" ? [
"storage.objects.delete",
"storage.objects.get",
"storage.objects.update"
] : [
] : [
"storage.objects.get",
"storage.objects.update"
]
project = var.project_id
provider = google
}

resource "google_storage_bucket_iam_binding" "binding_promote_bucket" {
count = var.promote_bucket != "" ? 1 : 0
resource "google_storage_bucket_iam_member" "binding_promote_bucket" {
count = local.promote_enabled != "" ? 1 : 0
bucket = var.promote_bucket
role = google_project_iam_custom_role.promote_and_quarantine_bucket_role.name
members = [
"serviceAccount:${google_service_account.service_account.email}",
]
depends_on = [
google_project_iam_custom_role.promote_and_quarantine_bucket_role
]
role = google_project_iam_custom_role.promote_bucket_role[0].id
member = "serviceAccount:${google_service_account.service_account.email}"
provider = google.promote_provider
}

resource "google_storage_bucket_iam_binding" "binding_quarantine_bucket" {
count = var.quarantine_bucket != "" ? 1 : 0
resource "google_storage_bucket_iam_member" "binding_quarantine_bucket" {
count = local.quarantine_enabled != "" ? 1 : 0
bucket = var.quarantine_bucket
role = google_project_iam_custom_role.promote_and_quarantine_bucket_role.name
members = [
"serviceAccount:${google_service_account.service_account.email}",
]
depends_on = [
google_project_iam_custom_role.promote_and_quarantine_bucket_role
]
role = google_project_iam_custom_role.quarantine_bucket_role[0].id
member = "serviceAccount:${google_service_account.service_account.email}"
provider = google.quarantine_provider
}

resource "google_storage_bucket_iam_binding" "binding_scanning_bucket" {
bucket = var.scanning_bucket
role = google_project_iam_custom_role.scanning_bucket_access_role.name
role = google_project_iam_custom_role.scanning_bucket_access_role.name
members = [
"serviceAccount:${google_service_account.service_account.email}",
]
Expand All @@ -92,44 +91,44 @@ resource "google_storage_bucket_iam_binding" "binding_scanning_bucket" {
}

resource "google_storage_bucket" "artifacts_bucket" {
name = "artifacts-promote-and-quarantine-plugin-${lower(random_id.deploy_suffix.hex)}"
location = var.region
project = var.project_id
name = "artifacts-promote-and-quarantine-plugin-${lower(random_id.deploy_suffix.hex)}"
location = var.region
project = var.project_id
uniform_bucket_level_access = true
force_destroy = true
force_destroy = true
}

resource "google_storage_bucket_object" "archive" {
name = "gcp-promote-and-quarantine-plugin.zip"
bucket = google_storage_bucket.artifacts_bucket.name
source = data.archive_file.source.output_path
name = "gcp-promote-and-quarantine-plugin.zip"
bucket = google_storage_bucket.artifacts_bucket.name
source = data.archive_file.source.output_path
content_type = "application/zip"

depends_on = [
depends_on = [
google_storage_bucket.artifacts_bucket,
data.archive_file.source
]
}

resource "google_cloudfunctions_function" "promote_and_quarantining_plugin" {
name = "${var.plugin_prefix}-promote-and-quarantine-${random_id.deploy_suffix.hex}"
description = "Promote and Quarantine plugin ${random_id.deploy_suffix.hex}"
name = "${var.plugin_prefix}-promote-and-quarantine-${random_id.deploy_suffix.hex}"
description = "Promote and Quarantine plugin ${random_id.deploy_suffix.hex}"
source_archive_bucket = google_storage_bucket.artifacts_bucket.name
source_archive_object = google_storage_bucket_object.archive.name
runtime = "python312"
entry_point = "main"
project = var.project_id
runtime = "python312"
entry_point = "main"
project = var.project_id

event_trigger {
event_type = "providers/cloud.pubsub/eventTypes/topic.publish"
resource = "projects/${var.project_id}/topics/${var.scan_result_topic}"
resource = "projects/${var.project_id}/topics/${var.scan_result_topic}"
}

environment_variables = {
QUARANTINE_STORAGE_BUCKET = var.quarantine_bucket
QUARANTINE_MODE = var.quarantine_mode
PROMOTE_STORAGE_BUCKET = var.promote_bucket
PROMOTE_MODE = var.promote_mode
QUARANTINE_MODE = var.quarantine_mode
PROMOTE_STORAGE_BUCKET = var.promote_bucket
PROMOTE_MODE = var.promote_mode
}

service_account_email = google_service_account.service_account.email
Expand Down
25 changes: 25 additions & 0 deletions post-scan-actions/gcp-python-promote-or-quarantine/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.11.0"
}
}
}

provider "google" {
project = var.project_id
region = var.region
}

provider "google" {
alias = "quarantine_provider"
project = var.quarantine_bucket_properties.project_id != "" ? var.quarantine_bucket_properties.project_id : var.project_id
region = var.quarantine_bucket_properties.region != "" ? var.quarantine_bucket_properties.region : var.region
}

provider "google" {
alias = "promote_provider"
project = var.promote_bucket_properties.project_id != "" ? var.promote_bucket_properties.project_id : var.project_id
region = var.promote_bucket_properties.region != "" ? var.promote_bucket_properties.region : var.region
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
google-cloud-storage==2.14.0
google-cloud-storage==2.16.0
144 changes: 83 additions & 61 deletions post-scan-actions/gcp-python-promote-or-quarantine/variables.tf
Original file line number Diff line number Diff line change
@@ -1,61 +1,83 @@
variable "project_id" {
type = string
description = "ID of the GCP project which the plugin will be deployed"
sensitive = true
}

variable "region" {
type = string
description = "GCP region to deploy the plugin"
}

variable "plugin_prefix" {
type = string
description = "GCP function prefix to use for the plugin"
}

variable "deployment_name" {
type = string
description = "The name of the deployment"
}

variable "scan_result_topic" {
type = string
description = "The name of the Pub/Sub topic for scan results topic"
}

variable "scanning_bucket" {
type = string
description = "Scanning bucket name"
nullable = false
}

variable "quarantine_mode" {
type = string
description = "The quarantine mode to use: 'move' or 'copy'"
nullable = false
validation {
condition = contains(["move", "copy"], var.quarantine_mode)
error_message = "Value must be one of 'move' or 'copy'."
}
}

variable "quarantine_bucket" {
type = string
description = "The quarantine bucket to use. Leave it empty if you don't want to quarantine files."
}

variable "promote_mode" {
type = string
description = "The promote mode to use: 'move' or 'copy'"
nullable = false
validation {
condition = contains(["move", "copy"], var.promote_mode)
error_message = "Value must be one of 'move' or 'copy'."
}
}

variable "promote_bucket" {
type = string
description = "The promote bucket to use. Leave it empty if you don't want to promote files."
}
variable "project_id" {
type = string
description = "ID of the GCP project which the plugin will be deployed"
sensitive = true
}

variable "region" {
type = string
description = "GCP region to deploy the plugin"
}

variable "plugin_prefix" {
type = string
description = "GCP function prefix to use for the plugin"
}

variable "deployment_name" {
type = string
description = "The name of the deployment"
}

variable "scan_result_topic" {
type = string
description = "The name of the Pub/Sub topic for scan results topic"
}

variable "scanning_bucket" {
type = string
description = "Scanning bucket name"
nullable = false
}

variable "quarantine_mode" {
type = string
description = "The quarantine mode to use: 'move' or 'copy'"
nullable = false
validation {
condition = contains(["move", "copy"], var.quarantine_mode)
error_message = "Value must be one of 'move' or 'copy'."
}
default = "move"
}

variable "quarantine_bucket" {
type = string
description = "The quarantine bucket to use. Leave it empty if you don't want to quarantine files."
nullable = true
default = ""
}

variable "quarantine_bucket_properties" {
type = object({
project_id = string
region = string
})
description = "The properties of the quarantine bucket including the following: gcp project, location, CMEK used."
}

variable "promote_mode" {
type = string
description = "The promote mode to use: 'move' or 'copy'"
nullable = false
validation {
condition = contains(["move", "copy"], var.promote_mode)
error_message = "Value must be one of 'move' or 'copy'."
}
default = "move"
}

variable "promote_bucket" {
type = string
description = "The promote bucket to use. Leave it empty if you don't want to promote files."
nullable = true
default = ""
}

variable "promote_bucket_properties" {
type = object({
project_id = string
region = string
})
description = "The properties of the promote bucket including the following: gcp project, location, CMEK used."
}

0 comments on commit 795fbe3

Please sign in to comment.