From c5e54065c782bb9e40dcf0bb2ba1a52be64f59f2 Mon Sep 17 00:00:00 2001 From: Joshua Wright Date: Thu, 5 Dec 2024 12:27:06 +0000 Subject: [PATCH 1/6] Add Default API Alerts --- modules/project/README.md | 39 ++- modules/project/api_metrics_alerts.tf | 361 ++++++++++++++++++++++++++ modules/project/variables.tf | 11 + 3 files changed, 408 insertions(+), 3 deletions(-) create mode 100644 modules/project/api_metrics_alerts.tf diff --git a/modules/project/README.md b/modules/project/README.md index 62bb6fea6d..cee73e2bd1 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -29,9 +29,7 @@ This module implements the creation and management of one GCP project including - [VPC Service Controls](#vpc-service-controls) - [Project Related Outputs](#project-related-outputs) - [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it) -- [Files](#files) -- [Variables](#variables) -- [Outputs](#outputs) +- [tftest inventory=data.yaml e2e](#tftest-inventorydatayaml-e2e) ## Basic Project Creation @@ -1357,6 +1355,38 @@ module "bucket" { parent = var.project_id id = "${var.prefix}-bucket" } + +## API Alerts +There are events within Google Cloud that should be monitored and alerted on to ensure that you are aware of any potential security issues. +These actions are typically seen in cases of security breaches, or potential security breaches, although they can be genuine actions that are not security related, but are still important to monitor. +These events are typically +- Owner Role Assignment/Changes +- Audit Logging Configuration Changes +- Custom Roles Creation/editing/deletion +- VPC Network Firewall Rule Changes +- VPC Network Route Changes +- VPC Network Changes +- Cloud Storage IAM Permission Changes +- SQL Instances Configuration Changes +Although you may not use the services listed above, such as SQL, it is still important to monitor these events for compliance purposes +To enable these alerts by default on all projects created, it is recommended to default the variable `enable_default_api_alerts` within `variables.tf` to true, +You will also need to set the `default_api_alerts_email` variable to the email address that will receive these alerts +You can alternatively enable these alerts on a per-project basis by setting the variable `enable_api_alerts` to true on the module, along with the `default_api_alerts_email` variable +```terraform +module "project" { + source = "./fabric/modules/project" + billing_account = var.billing_account_id + name = "project" + parent = var.folder_id + prefix = var.prefix + services = [ + "stackdriver.googleapis.com" + ] + enable_api_alerts = true + default_api_alerts_email = "monitoring@company.com" +} +``` + # tftest inventory=data.yaml e2e ``` @@ -1366,6 +1396,7 @@ module "bucket" { | name | description | resources | |---|---|---| +| [api_metrics_alerts.tf](./api_metrics_alerts.tf) | None | google_logging_metric · google_monitoring_alert_policy · google_monitoring_notification_channel | | [cmek.tf](./cmek.tf) | Service Agent IAM Bindings for CMEK | google_kms_crypto_key_iam_member | | [iam.tf](./iam.tf) | IAM bindings. | google_project_iam_binding · google_project_iam_custom_role · google_project_iam_member | | [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member · google_logging_project_exclusion · google_logging_project_sink · google_project_iam_audit_config · google_project_iam_member · google_pubsub_topic_iam_member · google_storage_bucket_iam_member | @@ -1393,9 +1424,11 @@ module "bucket" { | [compute_metadata](variables.tf#L29) | Optional compute metadata key/values. Only usable if compute API has been enabled. | map(string) | | {} | | [contacts](variables.tf#L36) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | | [custom_roles](variables.tf#L43) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | +| [default_api_alerts_email](variables.tf#L323) | Email address to receive default API alerts | string | | null | | [default_service_account](variables.tf#L50) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" | | [deletion_policy](variables.tf#L64) | Deletion policy setting for this project. | string | | "DELETE" | | [descriptive_name](variables.tf#L75) | Name of the project name. Used for project name instead of `name` variable. | string | | null | +| [enable_default_api_alerts](variables.tf#L318) | Enable default API alerts for the project, when API alerts are required for compliance reasons | bool | | false | | [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | | [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | diff --git a/modules/project/api_metrics_alerts.tf b/modules/project/api_metrics_alerts.tf new file mode 100644 index 0000000000..fcc205a69f --- /dev/null +++ b/modules/project/api_metrics_alerts.tf @@ -0,0 +1,361 @@ +resource "google_monitoring_notification_channel" "email" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + display_name = "Default Email Notification" + type = "email" + labels = { + email_address = var.default_api_alerts_email + } +} + +# +# Route Changes Metric and Policy +# +resource "google_logging_metric" "route_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "resource.type=\"gce_route\" AND (protoPayload.methodName:\"compute.routes.delete\" OR protoPayload.methodName:\"compute.routes.insert\")" + name = "network-route-config-changes" + description = "Monitor VPC network route configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "route_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "Network Route Changes" + conditions { + display_name = "Network Route Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "resource.type = \"global\" AND metric.type = \"logging.googleapis.com/user/${google_logging_metric.route_changes[count.index].name}\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# Firewall Changes Metric and Policy +# +resource "google_logging_metric" "firewall_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "resource.type=\"gce_firewall_rule\" AND (protoPayload.methodName:\"compute.firewalls.insert\" OR protoPayload.methodName:\"compute.firewalls.patch\" OR protoPayload.methodName:\"compute.firewalls.delete\")" + name = "network-firewall-config-changes" + description = "Monitor VPC network firewall configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "firewall_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "VPC Network Firewalls Changes" + conditions { + display_name = "VPC Network Firewalls Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "resource.type = \"global\" AND metric.type = \"logging.googleapis.com/user/${google_logging_metric.firewall_changes[count.index].name}\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# VPC Changes Metric and Policy +# +resource "google_logging_metric" "vpc_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "resource.type=\"gce_network\" AND (protoPayload.methodName:\"compute.networks.insert\" OR protoPayload.methodName:\"compute.networks.patch\" OR protoPayload.methodName:\"compute.networks.delete\" OR protoPayload.methodName:\"compute.networks.removePeering\" OR protoPayload.methodName:\"compute.networks.addPeering\")" + name = "vpc-network-config-changes" + description = "Monitor VPC network configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "vpc_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "VPC Network Changes" + conditions { + display_name = "VPC Network Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "resource.type = \"global\" AND metric.type = \"logging.googleapis.com/user/${google_logging_metric.vpc_changes[count.index].name}\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# CloudSQL Changes +# +resource "google_logging_metric" "cloudsql_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "protoPayload.methodName=\"cloudsql.instances.update\" OR protoPayload.methodName=\"cloudsql.instances.create\" OR protoPayload.methodName=\"cloudsql.instances.delete\"" + name = "cloudsql-changes" + description = "Monitor Cloud SQL configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "cloudsql_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "CloudSQL Changes" + conditions { + display_name = "CloudSQL Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "metric.type = \"logging.googleapis.com/user/${google_logging_metric.cloudsql_changes[count.index].name}\" AND resource.type=\"global\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# Cloud Storage IAM Changes +# +resource "google_logging_metric" "cloudstorage_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "resource.type=gcs_bucket AND protoPayload.methodName=\"storage.setIamPermissions\"" + name = "cloudstorage-changes" + description = "Monitor Cloud Storage IAM configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "cloudstorage_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "CloudStorage IAM Changes" + conditions { + display_name = "CloudStorage IAM Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "resource.type = \"gcs_bucket\" AND metric.type = \"logging.googleapis.com/user/${google_logging_metric.cloudstorage_changes[count.index].name}\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# Custom Role IAM Changes +# +resource "google_logging_metric" "customrole_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "resource.type=\"iam_role\" AND (protoPayload.methodName=\"google.iam.admin.v1.CreateRole\" OR protoPayload.methodName=\"google.iam.admin.v1.DeleteRole\" OR protoPayload.methodName=\"google.iam.admin.v1.UpdateRole\")" + name = "customrole-changes" + description = "Monitor IAM Custom Role configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "customrole_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "IAM Custom Role Changes" + conditions { + display_name = "IAM Custom Role Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "metric.type = \"logging.googleapis.com/user/${google_logging_metric.customrole_changes[count.index].name}\" AND resource.type=\"global\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# Audit Configuration Changes +# +resource "google_logging_metric" "audit_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "protoPayload.methodName=\"SetIamPolicy\" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:*" + name = "audit-changes" + description = "Monitor Audit configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "audit_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "Audit Configuration Changes" + conditions { + display_name = "Audit Configuration Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "metric.type = \"logging.googleapis.com/user/${google_logging_metric.audit_changes[count.index].name}\" AND resource.type=\"global\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_MEAN" + cross_series_reducer = "REDUCE_COUNT" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} + +# +# IAM Owner Configuration Changes +# +resource "google_logging_metric" "owner_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + filter = "(protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\") AND (ProjectOwnership OR projectOwnerInvitee) OR (protoPayload.serviceData.policyDelta.bindingDeltas.action=\"REMOVE\" AND protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\") OR (protoPayload.serviceData.policyDelta.bindingDeltas.action=\"ADD\" AND protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\")" + name = "iam-owner-changes" + description = "Monitor IAM Owner configuration changes inside GCP projects" + metric_descriptor { + metric_kind = "DELTA" + value_type = "INT64" + } +} + +resource "google_monitoring_alert_policy" "owner_changes" { + count = var.enable_default_api_alerts ? 1 : 0 + project = local.project.project_id + combiner = "OR" + display_name = "Owner IAM Configuration Changes" + conditions { + display_name = "Owner IAM Configuration Changed" + condition_threshold { + comparison = "COMPARISON_GT" + duration = "0s" + filter = "metric.type = \"logging.googleapis.com/user/${google_logging_metric.owner_changes[count.index].name}\" AND resource.type=\"global\"" + trigger { + count = 1 + } + aggregations { + per_series_aligner = "ALIGN_DELTA" + cross_series_reducer = "REDUCE_SUM" + alignment_period = "600s" + } + } + } + notification_channels = [ + google_monitoring_notification_channel.email[count.index].id, + ] + alert_strategy { + auto_close = "604800s" + } +} diff --git a/modules/project/variables.tf b/modules/project/variables.tf index 88f59763a0..d2baeee541 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -314,3 +314,14 @@ variable "vpc_sc" { }) default = null } + +variable "enable_default_api_alerts" { + description = "Enable default API alerts for the project, when API alerts are required for compliance reasons" + type = bool + default = false +} +variable "default_api_alerts_email" { + description = "Email address to receive default API alerts" + type = string + default = null +} From c116f94348a964ff7180eba83b0d0948a8dceb82 Mon Sep 17 00:00:00 2001 From: Joshua Wright Date: Thu, 5 Dec 2024 12:33:58 +0000 Subject: [PATCH 2/6] Correct Display --- modules/project/README.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/project/README.md b/modules/project/README.md index cee73e2bd1..c5f791feff 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -29,7 +29,10 @@ This module implements the creation and management of one GCP project including - [VPC Service Controls](#vpc-service-controls) - [Project Related Outputs](#project-related-outputs) - [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it) -- [tftest inventory=data.yaml e2e](#tftest-inventorydatayaml-e2e) +- [API Alerts](#api-alerts) +- [Files](#files) +- [Variables](#variables) +- [Outputs](#outputs) ## Basic Project Creation @@ -1356,6 +1359,9 @@ module "bucket" { id = "${var.prefix}-bucket" } +# tftest inventory=data.yaml e2e +``` + ## API Alerts There are events within Google Cloud that should be monitored and alerted on to ensure that you are aware of any potential security issues. These actions are typically seen in cases of security breaches, or potential security breaches, although they can be genuine actions that are not security related, but are still important to monitor. @@ -1368,9 +1374,12 @@ These events are typically - VPC Network Changes - Cloud Storage IAM Permission Changes - SQL Instances Configuration Changes -Although you may not use the services listed above, such as SQL, it is still important to monitor these events for compliance purposes -To enable these alerts by default on all projects created, it is recommended to default the variable `enable_default_api_alerts` within `variables.tf` to true, -You will also need to set the `default_api_alerts_email` variable to the email address that will receive these alerts + + +Although you may not use the services listed above, such as SQL, it is still important to monitor these events for compliance purposes + +To enable these alerts by default on all projects created, it is recommended to default the variable `enable_default_api_alerts` within `variables.tf` to true, You will also need to set the `default_api_alerts_email` variable to the email address that will receive these alerts + You can alternatively enable these alerts on a per-project basis by setting the variable `enable_api_alerts` to true on the module, along with the `default_api_alerts_email` variable ```terraform module "project" { @@ -1387,9 +1396,6 @@ module "project" { } ``` -# tftest inventory=data.yaml e2e -``` - ## Files From f30b7d6a405103b0f3f72cf008c239468e31e465 Mon Sep 17 00:00:00 2001 From: Joshua Wright Date: Thu, 5 Dec 2024 12:52:50 +0000 Subject: [PATCH 3/6] Restructure Variable --- modules/project/README.md | 11 +++++--- modules/project/api_metrics_alerts.tf | 36 +++++++++++++-------------- modules/project/variables.tf | 14 +++++------ 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/modules/project/README.md b/modules/project/README.md index c5f791feff..0b2feed0f3 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -1376,11 +1376,12 @@ These events are typically - SQL Instances Configuration Changes -Although you may not use the services listed above, such as SQL, it is still important to monitor these events for compliance purposes +Although you may not use the services listed above, such as SQL, it is still important to monitor these events for compliance purposes -To enable these alerts by default on all projects created, it is recommended to default the variable `enable_default_api_alerts` within `variables.tf` to true, You will also need to set the `default_api_alerts_email` variable to the email address that will receive these alerts +To enable these alerts by default on all projects created, it is recommended to default the variable `api_slerts` within `variables.tf` to true, along with adding a default email address. You can alternatively enable these alerts on a per-project basis by setting the variable `enable_api_alerts` to true on the module, along with the `default_api_alerts_email` variable + ```terraform module "project" { source = "./fabric/modules/project" @@ -1391,8 +1392,10 @@ module "project" { services = [ "stackdriver.googleapis.com" ] - enable_api_alerts = true - default_api_alerts_email = "monitoring@company.com" + api_alerts = { + enable_api_alerts = true + default_api_alerts_email = "monitoring@company.com" + } } ``` diff --git a/modules/project/api_metrics_alerts.tf b/modules/project/api_metrics_alerts.tf index fcc205a69f..b8683e0373 100644 --- a/modules/project/api_metrics_alerts.tf +++ b/modules/project/api_metrics_alerts.tf @@ -1,10 +1,10 @@ resource "google_monitoring_notification_channel" "email" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id display_name = "Default Email Notification" type = "email" labels = { - email_address = var.default_api_alerts_email + email_address = var.api_alerts.email } } @@ -12,7 +12,7 @@ resource "google_monitoring_notification_channel" "email" { # Route Changes Metric and Policy # resource "google_logging_metric" "route_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "resource.type=\"gce_route\" AND (protoPayload.methodName:\"compute.routes.delete\" OR protoPayload.methodName:\"compute.routes.insert\")" name = "network-route-config-changes" @@ -24,7 +24,7 @@ resource "google_logging_metric" "route_changes" { } resource "google_monitoring_alert_policy" "route_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "Network Route Changes" @@ -56,7 +56,7 @@ resource "google_monitoring_alert_policy" "route_changes" { # Firewall Changes Metric and Policy # resource "google_logging_metric" "firewall_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "resource.type=\"gce_firewall_rule\" AND (protoPayload.methodName:\"compute.firewalls.insert\" OR protoPayload.methodName:\"compute.firewalls.patch\" OR protoPayload.methodName:\"compute.firewalls.delete\")" name = "network-firewall-config-changes" @@ -68,7 +68,7 @@ resource "google_logging_metric" "firewall_changes" { } resource "google_monitoring_alert_policy" "firewall_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "VPC Network Firewalls Changes" @@ -100,7 +100,7 @@ resource "google_monitoring_alert_policy" "firewall_changes" { # VPC Changes Metric and Policy # resource "google_logging_metric" "vpc_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "resource.type=\"gce_network\" AND (protoPayload.methodName:\"compute.networks.insert\" OR protoPayload.methodName:\"compute.networks.patch\" OR protoPayload.methodName:\"compute.networks.delete\" OR protoPayload.methodName:\"compute.networks.removePeering\" OR protoPayload.methodName:\"compute.networks.addPeering\")" name = "vpc-network-config-changes" @@ -112,7 +112,7 @@ resource "google_logging_metric" "vpc_changes" { } resource "google_monitoring_alert_policy" "vpc_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "VPC Network Changes" @@ -144,7 +144,7 @@ resource "google_monitoring_alert_policy" "vpc_changes" { # CloudSQL Changes # resource "google_logging_metric" "cloudsql_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "protoPayload.methodName=\"cloudsql.instances.update\" OR protoPayload.methodName=\"cloudsql.instances.create\" OR protoPayload.methodName=\"cloudsql.instances.delete\"" name = "cloudsql-changes" @@ -156,7 +156,7 @@ resource "google_logging_metric" "cloudsql_changes" { } resource "google_monitoring_alert_policy" "cloudsql_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "CloudSQL Changes" @@ -188,7 +188,7 @@ resource "google_monitoring_alert_policy" "cloudsql_changes" { # Cloud Storage IAM Changes # resource "google_logging_metric" "cloudstorage_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "resource.type=gcs_bucket AND protoPayload.methodName=\"storage.setIamPermissions\"" name = "cloudstorage-changes" @@ -200,7 +200,7 @@ resource "google_logging_metric" "cloudstorage_changes" { } resource "google_monitoring_alert_policy" "cloudstorage_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "CloudStorage IAM Changes" @@ -232,7 +232,7 @@ resource "google_monitoring_alert_policy" "cloudstorage_changes" { # Custom Role IAM Changes # resource "google_logging_metric" "customrole_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "resource.type=\"iam_role\" AND (protoPayload.methodName=\"google.iam.admin.v1.CreateRole\" OR protoPayload.methodName=\"google.iam.admin.v1.DeleteRole\" OR protoPayload.methodName=\"google.iam.admin.v1.UpdateRole\")" name = "customrole-changes" @@ -244,7 +244,7 @@ resource "google_logging_metric" "customrole_changes" { } resource "google_monitoring_alert_policy" "customrole_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "IAM Custom Role Changes" @@ -276,7 +276,7 @@ resource "google_monitoring_alert_policy" "customrole_changes" { # Audit Configuration Changes # resource "google_logging_metric" "audit_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "protoPayload.methodName=\"SetIamPolicy\" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:*" name = "audit-changes" @@ -288,7 +288,7 @@ resource "google_logging_metric" "audit_changes" { } resource "google_monitoring_alert_policy" "audit_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "Audit Configuration Changes" @@ -320,7 +320,7 @@ resource "google_monitoring_alert_policy" "audit_changes" { # IAM Owner Configuration Changes # resource "google_logging_metric" "owner_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id filter = "(protoPayload.serviceName=\"cloudresourcemanager.googleapis.com\") AND (ProjectOwnership OR projectOwnerInvitee) OR (protoPayload.serviceData.policyDelta.bindingDeltas.action=\"REMOVE\" AND protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\") OR (protoPayload.serviceData.policyDelta.bindingDeltas.action=\"ADD\" AND protoPayload.serviceData.policyDelta.bindingDeltas.role=\"roles/owner\")" name = "iam-owner-changes" @@ -332,7 +332,7 @@ resource "google_logging_metric" "owner_changes" { } resource "google_monitoring_alert_policy" "owner_changes" { - count = var.enable_default_api_alerts ? 1 : 0 + count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id combiner = "OR" display_name = "Owner IAM Configuration Changes" diff --git a/modules/project/variables.tf b/modules/project/variables.tf index d2baeee541..067753917d 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -315,13 +315,11 @@ variable "vpc_sc" { default = null } -variable "enable_default_api_alerts" { +variable "api_alerts" { description = "Enable default API alerts for the project, when API alerts are required for compliance reasons" - type = bool - default = false -} -variable "default_api_alerts_email" { - description = "Email address to receive default API alerts" - type = string - default = null + type = object({ + enabled = optional(bool, false) + email = optional(string, null) + }) + default = {} } From 224780fb3b25c47045e67beb838a6970eb9adb74 Mon Sep 17 00:00:00 2001 From: Joshua Wright Date: Thu, 5 Dec 2024 14:26:51 +0000 Subject: [PATCH 4/6] Restructure Variable --- modules/project/api_metrics_alerts.tf | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/project/api_metrics_alerts.tf b/modules/project/api_metrics_alerts.tf index b8683e0373..6b36ae714d 100644 --- a/modules/project/api_metrics_alerts.tf +++ b/modules/project/api_metrics_alerts.tf @@ -1,3 +1,20 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +# tfdoc:file:description Add API Alerts resource "google_monitoring_notification_channel" "email" { count = var.api_alerts.enabled ? 1 : 0 project = local.project.project_id From 4b28d2a00a54441af39941899a8cff9fb17527b5 Mon Sep 17 00:00:00 2001 From: Joshua Wright Date: Thu, 5 Dec 2024 14:33:40 +0000 Subject: [PATCH 5/6] Correct Documentation --- modules/project/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/project/README.md b/modules/project/README.md index 0b2feed0f3..ad49f81498 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -1405,7 +1405,7 @@ module "project" { | name | description | resources | |---|---|---| -| [api_metrics_alerts.tf](./api_metrics_alerts.tf) | None | google_logging_metric · google_monitoring_alert_policy · google_monitoring_notification_channel | +| [api_metrics_alerts.tf](./api_metrics_alerts.tf) | Add API Alerts | google_logging_metric · google_monitoring_alert_policy · google_monitoring_notification_channel | | [cmek.tf](./cmek.tf) | Service Agent IAM Bindings for CMEK | google_kms_crypto_key_iam_member | | [iam.tf](./iam.tf) | IAM bindings. | google_project_iam_binding · google_project_iam_custom_role · google_project_iam_member | | [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member · google_logging_project_exclusion · google_logging_project_sink · google_project_iam_audit_config · google_project_iam_member · google_pubsub_topic_iam_member · google_storage_bucket_iam_member | @@ -1428,16 +1428,15 @@ module "project" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [name](variables.tf#L165) | Project name and id suffix. | string | ✓ | | +| [api_alerts](variables.tf#L318) | Enable default API alerts for the project, when API alerts are required for compliance reasons | object({…}) | | {} | | [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | bool | | false | | [billing_account](variables.tf#L23) | Billing account id. | string | | null | | [compute_metadata](variables.tf#L29) | Optional compute metadata key/values. Only usable if compute API has been enabled. | map(string) | | {} | | [contacts](variables.tf#L36) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | | [custom_roles](variables.tf#L43) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | -| [default_api_alerts_email](variables.tf#L323) | Email address to receive default API alerts | string | | null | | [default_service_account](variables.tf#L50) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" | | [deletion_policy](variables.tf#L64) | Deletion policy setting for this project. | string | | "DELETE" | | [descriptive_name](variables.tf#L75) | Name of the project name. Used for project name instead of `name` variable. | string | | null | -| [enable_default_api_alerts](variables.tf#L318) | Enable default API alerts for the project, when API alerts are required for compliance reasons | bool | | false | | [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | | [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | From f754a939baf8c1b461a1a4f748e386676b77a43e Mon Sep 17 00:00:00 2001 From: Joshua Wright Date: Thu, 5 Dec 2024 15:45:08 +0000 Subject: [PATCH 6/6] Correct Documentation --- modules/project/README.md | 58 ++++++++++++++++++------------------ modules/project/variables.tf | 18 +++++------ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/modules/project/README.md b/modules/project/README.md index ad49f81498..5a71b1332d 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -1427,43 +1427,43 @@ module "project" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L165) | Project name and id suffix. | string | ✓ | | -| [api_alerts](variables.tf#L318) | Enable default API alerts for the project, when API alerts are required for compliance reasons | object({…}) | | {} | -| [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | bool | | false | -| [billing_account](variables.tf#L23) | Billing account id. | string | | null | -| [compute_metadata](variables.tf#L29) | Optional compute metadata key/values. Only usable if compute API has been enabled. | map(string) | | {} | -| [contacts](variables.tf#L36) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | -| [custom_roles](variables.tf#L43) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | -| [default_service_account](variables.tf#L50) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" | -| [deletion_policy](variables.tf#L64) | Deletion policy setting for this project. | string | | "DELETE" | -| [descriptive_name](variables.tf#L75) | Name of the project name. Used for project name instead of `name` variable. | string | | null | -| [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | +| [name](variables.tf#L174) | Project name and id suffix. | string | ✓ | | +| [api_alerts](variables.tf#L17) | Enable default API alerts for the project. | object({…}) | | {} | +| [auto_create_network](variables.tf#L26) | Whether to create the default network for the project. | bool | | false | +| [billing_account](variables.tf#L32) | Billing account id. | string | | null | +| [compute_metadata](variables.tf#L38) | Optional compute metadata key/values. Only usable if compute API has been enabled. | map(string) | | {} | +| [contacts](variables.tf#L45) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | +| [custom_roles](variables.tf#L52) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | +| [default_service_account](variables.tf#L59) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" | +| [deletion_policy](variables.tf#L73) | Deletion policy setting for this project. | string | | "DELETE" | +| [descriptive_name](variables.tf#L84) | Name of the project name. Used for project name instead of `name` variable. | string | | null | +| [factories_config](variables.tf#L90) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | | [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | | [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | [iam_by_principals](variables-iam.tf#L54) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | -| [labels](variables.tf#L92) | Resource labels. | map(string) | | {} | -| [lien_reason](variables.tf#L99) | If non-empty, creates a project lien with this description. | string | | null | -| [logging_data_access](variables.tf#L105) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string))) | | {} | -| [logging_exclusions](variables.tf#L120) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_sinks](variables.tf#L127) | Logging sinks to create for this project. | map(object({…})) | | {} | -| [metric_scopes](variables.tf#L158) | List of projects that will act as metric scopes for this project. | list(string) | | [] | +| [labels](variables.tf#L101) | Resource labels. | map(string) | | {} | +| [lien_reason](variables.tf#L108) | If non-empty, creates a project lien with this description. | string | | null | +| [logging_data_access](variables.tf#L114) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string))) | | {} | +| [logging_exclusions](variables.tf#L129) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} | +| [logging_sinks](variables.tf#L136) | Logging sinks to create for this project. | map(object({…})) | | {} | +| [metric_scopes](variables.tf#L167) | List of projects that will act as metric scopes for this project. | list(string) | | [] | | [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | -| [org_policies](variables.tf#L170) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | -| [parent](variables.tf#L197) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | -| [prefix](variables.tf#L207) | Optional prefix used to generate project id and name. | string | | null | -| [project_create](variables.tf#L217) | Create project. When set to false, uses a data source to reference existing project. | bool | | true | +| [org_policies](variables.tf#L179) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | +| [parent](variables.tf#L206) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | +| [prefix](variables.tf#L216) | Optional prefix used to generate project id and name. | string | | null | +| [project_create](variables.tf#L226) | Create project. When set to false, uses a data source to reference existing project. | bool | | true | | [quotas](variables-quotas.tf#L17) | Service quota configuration. | map(object({…})) | | {} | -| [service_agents_config](variables.tf#L223) | Automatic service agent configuration options. | object({…}) | | {} | -| [service_config](variables.tf#L234) | Configure service API activation. | object({…}) | | {…} | -| [service_encryption_key_ids](variables.tf#L246) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string)) | | {} | -| [services](variables.tf#L253) | Service APIs to enable. | list(string) | | [] | -| [shared_vpc_host_config](variables.tf#L259) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | -| [shared_vpc_service_config](variables.tf#L268) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} | -| [skip_delete](variables.tf#L296) | Deprecated. Use deletion_policy. | bool | | null | +| [service_agents_config](variables.tf#L232) | Automatic service agent configuration options. | object({…}) | | {} | +| [service_config](variables.tf#L243) | Configure service API activation. | object({…}) | | {…} | +| [service_encryption_key_ids](variables.tf#L255) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string)) | | {} | +| [services](variables.tf#L262) | Service APIs to enable. | list(string) | | [] | +| [shared_vpc_host_config](variables.tf#L268) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | +| [shared_vpc_service_config](variables.tf#L277) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} | +| [skip_delete](variables.tf#L305) | Deprecated. Use deletion_policy. | bool | | null | | [tag_bindings](variables-tags.tf#L81) | Tag bindings for this project, in key => tag value id format. | map(string) | | null | | [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | -| [vpc_sc](variables.tf#L308) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null | +| [vpc_sc](variables.tf#L317) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null | ## Outputs diff --git a/modules/project/variables.tf b/modules/project/variables.tf index 067753917d..4a9954d4a2 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -14,6 +14,15 @@ * limitations under the License. */ +variable "api_alerts" { + description = "Enable default API alerts for the project." + type = object({ + enabled = optional(bool, false) + email = optional(string, null) + }) + default = {} +} + variable "auto_create_network" { description = "Whether to create the default network for the project." type = bool @@ -314,12 +323,3 @@ variable "vpc_sc" { }) default = null } - -variable "api_alerts" { - description = "Enable default API alerts for the project, when API alerts are required for compliance reasons" - type = object({ - enabled = optional(bool, false) - email = optional(string, null) - }) - default = {} -}