From 171a2c66908ae27c03b190a0b3f1440aff038d55 Mon Sep 17 00:00:00 2001 From: Vannick Trinquier Date: Thu, 4 Dec 2025 17:01:32 +0700 Subject: [PATCH] Add support for CMEK in logging bucket, big query dataset and gke notifications (#3558) --- modules/bigquery-dataset/README.md | 32 +++++------ modules/bigquery-dataset/main.tf | 15 ++++- modules/bigquery-dataset/variables.tf | 1 + modules/gke-cluster-autopilot/README.md | 57 ++++++++++++++----- modules/gke-cluster-autopilot/main.tf | 1 + modules/gke-cluster-autopilot/variables.tf | 7 ++- modules/gke-cluster-standard/README.md | 39 ++++++------- modules/gke-cluster-standard/main.tf | 1 + modules/gke-cluster-standard/variables.tf | 7 ++- modules/logging-bucket/README.md | 22 +++---- modules/logging-bucket/main.tf | 3 +- modules/logging-bucket/variables.tf | 1 + modules/project-factory/README.md | 2 +- modules/project-factory/projects-bigquery.tf | 16 +++--- modules/project-factory/projects-buckets.tf | 2 +- modules/project-factory/variables-projects.tf | 5 +- modules/project/cmek.tf | 5 +- tests/modules/bigquery_dataset/context.tfvars | 10 +++- tests/modules/bigquery_dataset/context.yaml | 3 +- .../examples/notifications.yaml | 48 ++++++++++++++++ .../examples/notifications.yaml | 2 +- tests/modules/logging_bucket/context.tfvars | 10 +++- tests/modules/logging_bucket/context.yaml | 3 +- 23 files changed, 199 insertions(+), 93 deletions(-) create mode 100644 tests/modules/gke_cluster_autopilot/examples/notifications.yaml diff --git a/modules/bigquery-dataset/README.md b/modules/bigquery-dataset/README.md index 44f25427c..cd9433052 100644 --- a/modules/bigquery-dataset/README.md +++ b/modules/bigquery-dataset/README.md @@ -353,27 +353,27 @@ module "bigquery-dataset" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [id](variables.tf#L111) | Dataset id. | string | ✓ | | -| [project_id](variables.tf#L175) | Id of the project where datasets will be created. | string | ✓ | | +| [id](variables.tf#L112) | Dataset id. | string | ✓ | | +| [project_id](variables.tf#L176) | Id of the project where datasets will be created. | string | ✓ | | | [access](variables.tf#L17) | Map of access rules with role and identity type. Keys are arbitrary and must match those in the `access_identities` variable, types are `domain`, `group`, `special_group`, `user`, `view`. | map(object({…})) | | {} | | [access_identities](variables.tf#L33) | Map of access identities used for basic access roles. View identities have the format 'project_id\|dataset_id\|table_id'. | map(string) | | {} | | [authorized_datasets](variables.tf#L39) | An array of datasets to be authorized on the dataset. | list(object({…})) | | [] | | [authorized_routines](variables.tf#L48) | An array of routines to be authorized on the dataset. | list(object({…})) | | [] | | [authorized_views](variables.tf#L58) | An array of views to be authorized on the dataset. | list(object({…})) | | [] | -| [context](variables.tf#L68) | Context-specific interpolations. | object({…}) | | {} | -| [dataset_access](variables.tf#L81) | Set access in the dataset resource instead of using separate resources. | bool | | false | -| [description](variables.tf#L87) | Optional description. | string | | "Terraform managed." | -| [encryption_key](variables.tf#L93) | Self link of the KMS key that will be used to protect destination table. | string | | null | -| [friendly_name](variables.tf#L99) | Dataset friendly name. | string | | null | -| [iam](variables.tf#L105) | IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles. | map(list(string)) | | {} | -| [labels](variables.tf#L116) | Dataset labels. | map(string) | | {} | -| [location](variables.tf#L122) | Dataset location. | string | | "EU" | -| [materialized_views](variables.tf#L128) | Materialized views definitions. | map(object({…})) | | {} | -| [options](variables.tf#L161) | Dataset options. | object({…}) | | {} | -| [routines](variables.tf#L180) | Routine definitions. | map(object({…})) | | {} | -| [tables](variables.tf#L219) | Table definitions. Options and partitioning default to null. Partitioning can only use `range` or `time`, set the unused one to null. | map(object({…})) | | {} | -| [tag_bindings](variables.tf#L304) | Tag bindings for this dataset, in key => tag value id format. | map(string) | | {} | -| [views](variables.tf#L311) | View definitions. | map(object({…})) | | {} | +| [context](variables.tf#L68) | Context-specific interpolations. | object({…}) | | {} | +| [dataset_access](variables.tf#L82) | Set access in the dataset resource instead of using separate resources. | bool | | false | +| [description](variables.tf#L88) | Optional description. | string | | "Terraform managed." | +| [encryption_key](variables.tf#L94) | Self link of the KMS key that will be used to protect destination table. | string | | null | +| [friendly_name](variables.tf#L100) | Dataset friendly name. | string | | null | +| [iam](variables.tf#L106) | IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles. | map(list(string)) | | {} | +| [labels](variables.tf#L117) | Dataset labels. | map(string) | | {} | +| [location](variables.tf#L123) | Dataset location. | string | | "EU" | +| [materialized_views](variables.tf#L129) | Materialized views definitions. | map(object({…})) | | {} | +| [options](variables.tf#L162) | Dataset options. | object({…}) | | {} | +| [routines](variables.tf#L181) | Routine definitions. | map(object({…})) | | {} | +| [tables](variables.tf#L220) | Table definitions. Options and partitioning default to null. Partitioning can only use `range` or `time`, set the unused one to null. | map(object({…})) | | {} | +| [tag_bindings](variables.tf#L305) | Tag bindings for this dataset, in key => tag value id format. | map(string) | | {} | +| [views](variables.tf#L312) | View definitions. | map(object({…})) | | {} | ## Outputs diff --git a/modules/bigquery-dataset/main.tf b/modules/bigquery-dataset/main.tf index 17b676848..20a5fd520 100644 --- a/modules/bigquery-dataset/main.tf +++ b/modules/bigquery-dataset/main.tf @@ -43,7 +43,8 @@ locals { for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv } if k != "condition_vars" } - ctx_p = "$" + ctx_p = "$" + ctx_kms_keys = try(local.ctx.kms_keys, {}) identities_view = { for k, v in local.access_view : k => try( zipmap( @@ -144,7 +145,11 @@ resource "google_bigquery_dataset" "default" { dynamic "default_encryption_configuration" { for_each = var.encryption_key == null ? [] : [""] content { - kms_key_name = var.encryption_key + kms_key_name = lookup( + local.ctx_kms_keys, + var.encryption_key, + var.encryption_key + ) } } } @@ -255,7 +260,11 @@ resource "google_bigquery_table" "default" { dynamic "encryption_configuration" { for_each = each.value.options.encryption_key != null ? [""] : [] content { - kms_key_name = each.value.options.encryption_key + kms_key_name = lookup( + local.ctx_kms_keys, + each.value.options.encryption_key, + each.value.options.encryption_key + ) } } diff --git a/modules/bigquery-dataset/variables.tf b/modules/bigquery-dataset/variables.tf index 9e797b3f4..dac68063f 100644 --- a/modules/bigquery-dataset/variables.tf +++ b/modules/bigquery-dataset/variables.tf @@ -69,6 +69,7 @@ variable "context" { description = "Context-specific interpolations." type = object({ custom_roles = optional(map(string), {}) + kms_keys = optional(map(string), {}) iam_principals = optional(map(string), {}) locations = optional(map(string), {}) project_ids = optional(map(string), {}) diff --git a/modules/gke-cluster-autopilot/README.md b/modules/gke-cluster-autopilot/README.md index 29098884c..51cb7cb07 100644 --- a/modules/gke-cluster-autopilot/README.md +++ b/modules/gke-cluster-autopilot/README.md @@ -10,6 +10,7 @@ This module offers a way to create and manage Google Kubernetes Engine (GKE) [Au - [Backup for GKE](#backup-for-gke) - [Allowing access from Google Cloud services](#allowing-access-from-google-cloud-services) - [Disable PSC endpoint creation](#disable-psc-endpoint-creation) +- [Upgrade notifications](#upgrade-notifications) - [Variables](#variables) - [Outputs](#outputs) @@ -263,31 +264,57 @@ module "cluster-1" { } # tftest modules=1 resources=1 inventory=no-ip-access.yaml ``` + +## Upgrade notifications + +Upgrade notifications are configured via the `enable_features.upgrade_notifications`. An existing PubSub topic can be defined via its `topic` attribute, or a new one can be created if the attribute is not set. The `event_types` attribute can be used to control which event types are sent. The `kms_key_name` attribute can be used to control which KMS key is used to encrypt the notification messages. + +```hcl +module "cluster-1" { + source = "./fabric/modules/gke-cluster-autopilot" + project_id = var.project_id + name = "cluster-1" + location = "europe-west1" + vpc_config = { + network = var.vpc.self_link + subnetwork = var.subnet.self_link + secondary_range_names = {} + } + enable_features = { + upgrade_notifications = { + event_types = ["SECURITY_BULLETIN_EVENT", "UPGRADE_EVENT"] + kms_key_name = "projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey" + } + } +} +# tftest modules=1 resources=2 inventory=notifications.yaml +``` + ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [location](variables.tf#L172) | Autopilot clusters are always regional. | string | ✓ | | -| [name](variables.tf#L251) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L284) | Cluster project ID. | string | ✓ | | -| [vpc_config](variables.tf#L300) | VPC-level configuration. | object({…}) | ✓ | | +| [location](variables.tf#L173) | Autopilot clusters are always regional. | string | ✓ | | +| [name](variables.tf#L252) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L285) | Cluster project ID. | string | ✓ | | +| [vpc_config](variables.tf#L301) | VPC-level configuration. | object({…}) | ✓ | | | [access_config](variables.tf#L17) | Control plane endpoint and nodes access configurations. | object({…}) | | {} | | [backup_configs](variables.tf#L45) | Configuration for Backup for GKE. | object({…}) | | {} | | [deletion_protection](variables.tf#L67) | Whether or not to allow Terraform to destroy the cluster. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the cluster will fail. | bool | | true | | [description](variables.tf#L74) | Cluster description. | string | | null | | [enable_addons](variables.tf#L80) | Addons enabled in the cluster (true means enabled). | object({…}) | | {} | -| [enable_features](variables.tf#L94) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | -| [fleet_project](variables.tf#L154) | The name of the fleet host project where this cluster will be registered. | string | | null | -| [issue_client_certificate](variables.tf#L160) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L166) | Cluster resource labels. | map(string) | | null | -| [logging_config](variables.tf#L177) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L188) | Maintenance window configuration. | object({…}) | | {…} | -| [min_master_version](variables.tf#L211) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L217) | Monitoring configuration. System metrics collection cannot be disabled. Control plane metrics are optional. Kube state metrics are optional. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | -| [node_config](variables.tf#L256) | Configuration for nodes and nodepools. | object({…}) | | {} | -| [node_locations](variables.tf#L277) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [release_channel](variables.tf#L289) | Release channel for GKE upgrades. Clusters created in the Autopilot mode must use a release channel. Choose between \"RAPID\", \"REGULAR\", and \"STABLE\". | string | | "REGULAR" | +| [enable_features](variables.tf#L94) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | +| [fleet_project](variables.tf#L155) | The name of the fleet host project where this cluster will be registered. | string | | null | +| [issue_client_certificate](variables.tf#L161) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L167) | Cluster resource labels. | map(string) | | null | +| [logging_config](variables.tf#L178) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L189) | Maintenance window configuration. | object({…}) | | {…} | +| [min_master_version](variables.tf#L212) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L218) | Monitoring configuration. System metrics collection cannot be disabled. Control plane metrics are optional. Kube state metrics are optional. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | +| [node_config](variables.tf#L257) | Configuration for nodes and nodepools. | object({…}) | | {} | +| [node_locations](variables.tf#L278) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [release_channel](variables.tf#L290) | Release channel for GKE upgrades. Clusters created in the Autopilot mode must use a release channel. Choose between \"RAPID\", \"REGULAR\", and \"STABLE\". | string | | "REGULAR" | ## Outputs diff --git a/modules/gke-cluster-autopilot/main.tf b/modules/gke-cluster-autopilot/main.tf index 7c88fe180..cc1ee97c9 100644 --- a/modules/gke-cluster-autopilot/main.tf +++ b/modules/gke-cluster-autopilot/main.tf @@ -438,4 +438,5 @@ resource "google_pubsub_topic" "notifications" { labels = { content = "gke-notifications" } + kms_key_name = try(var.enable_features.upgrade_notifications.kms_key_name, null) } diff --git a/modules/gke-cluster-autopilot/variables.tf b/modules/gke-cluster-autopilot/variables.tf index 108bdf0e4..5fef3ee4a 100644 --- a/modules/gke-cluster-autopilot/variables.tf +++ b/modules/gke-cluster-autopilot/variables.tf @@ -131,9 +131,10 @@ variable "enable_features" { service_external_ips = optional(bool, true) tpu = optional(bool, false) upgrade_notifications = optional(object({ - enabled = optional(bool, true) - event_types = optional(list(string), []) - topic_id = optional(string) + enabled = optional(bool, true) + event_types = optional(list(string), []) + topic_id = optional(string) + kms_key_name = optional(string) })) vertical_pod_autoscaling = optional(bool, false) enterprise_cluster = optional(bool) diff --git a/modules/gke-cluster-standard/README.md b/modules/gke-cluster-standard/README.md index 49600d0b3..5341ae643 100644 --- a/modules/gke-cluster-standard/README.md +++ b/modules/gke-cluster-standard/README.md @@ -225,7 +225,7 @@ module "cluster-1" { ## Upgrade notifications -Upgrade notifications are configured via the `enable_features.upgrade_notifications`. An existing PubSub topic can be defined via its `topic` attribute, or a new one can be created if the attribute is not set. The `event_types` attribute can be used to control which event types are sent. +Upgrade notifications are configured via the `enable_features.upgrade_notifications`. An existing PubSub topic can be defined via its `topic` attribute, or a new one can be created if the attribute is not set. The `event_types` attribute can be used to control which event types are sent. The `kms_key_name` attribute can be used to control which KMS key is used to encrypt the notification messages. ```hcl module "cluster-1" { @@ -240,7 +240,8 @@ module "cluster-1" { } enable_features = { upgrade_notifications = { - event_types = ["SECURITY_BULLETIN_EVENT", "UPGRADE_EVENT"] + event_types = ["SECURITY_BULLETIN_EVENT", "UPGRADE_EVENT"] + kms_key_name = "projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey" } } } @@ -510,10 +511,10 @@ module "cluster-1" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [location](variables.tf#L292) | Cluster zone or region. | string | ✓ | | -| [name](variables.tf#L407) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L459) | Cluster project id. | string | ✓ | | -| [vpc_config](variables.tf#L470) | VPC-level configuration. | object({…}) | ✓ | | +| [location](variables.tf#L293) | Cluster zone or region. | string | ✓ | | +| [name](variables.tf#L408) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L460) | Cluster project id. | string | ✓ | | +| [vpc_config](variables.tf#L471) | VPC-level configuration. | object({…}) | ✓ | | | [access_config](variables.tf#L17) | Control plane endpoint and nodes access configurations. | object({…}) | | {} | | [backup_configs](variables.tf#L45) | Configuration for Backup for GKE. | object({…}) | | {} | | [cluster_autoscaling](variables.tf#L68) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | object({…}) | | null | @@ -521,19 +522,19 @@ module "cluster-1" { | [deletion_protection](variables.tf#L166) | Whether or not to allow Terraform to destroy the cluster. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the cluster will fail. | bool | | true | | [description](variables.tf#L173) | Cluster description. | string | | null | | [enable_addons](variables.tf#L179) | Addons enabled in the cluster (true means enabled). | object({…}) | | {} | -| [enable_features](variables.tf#L201) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | -| [fleet_project](variables.tf#L273) | The name of the fleet host project where this cluster will be registered. | string | | null | -| [issue_client_certificate](variables.tf#L279) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L285) | Cluster resource labels. | map(string) | | {} | -| [logging_config](variables.tf#L297) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L318) | Maintenance window configuration. | object({…}) | | {…} | -| [max_pods_per_node](variables.tf#L341) | Maximum number of pods per node in this cluster. | number | | 110 | -| [min_master_version](variables.tf#L347) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L353) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | -| [node_config](variables.tf#L412) | Node-level configuration. | object({…}) | | {} | -| [node_locations](variables.tf#L435) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [node_pool_auto_config](variables.tf#L442) | Node pool configs that apply to auto-provisioned node pools in autopilot clusters and node auto-provisioning-enabled clusters. | object({…}) | | {} | -| [release_channel](variables.tf#L464) | Release channel for GKE upgrades. | string | | null | +| [enable_features](variables.tf#L201) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | +| [fleet_project](variables.tf#L274) | The name of the fleet host project where this cluster will be registered. | string | | null | +| [issue_client_certificate](variables.tf#L280) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L286) | Cluster resource labels. | map(string) | | {} | +| [logging_config](variables.tf#L298) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L319) | Maintenance window configuration. | object({…}) | | {…} | +| [max_pods_per_node](variables.tf#L342) | Maximum number of pods per node in this cluster. | number | | 110 | +| [min_master_version](variables.tf#L348) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L354) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | +| [node_config](variables.tf#L413) | Node-level configuration. | object({…}) | | {} | +| [node_locations](variables.tf#L436) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [node_pool_auto_config](variables.tf#L443) | Node pool configs that apply to auto-provisioned node pools in autopilot clusters and node auto-provisioning-enabled clusters. | object({…}) | | {} | +| [release_channel](variables.tf#L465) | Release channel for GKE upgrades. | string | | null | ## Outputs diff --git a/modules/gke-cluster-standard/main.tf b/modules/gke-cluster-standard/main.tf index 35800b993..0e96ec986 100644 --- a/modules/gke-cluster-standard/main.tf +++ b/modules/gke-cluster-standard/main.tf @@ -689,4 +689,5 @@ resource "google_pubsub_topic" "notifications" { labels = { content = "gke-notifications" } + kms_key_name = try(var.enable_features.upgrade_notifications.kms_key_name, null) } diff --git a/modules/gke-cluster-standard/variables.tf b/modules/gke-cluster-standard/variables.tf index 7d41db0f9..1c5a105c6 100644 --- a/modules/gke-cluster-standard/variables.tf +++ b/modules/gke-cluster-standard/variables.tf @@ -243,9 +243,10 @@ variable "enable_features" { shielded_nodes = optional(bool, false) tpu = optional(bool, false) upgrade_notifications = optional(object({ - enabled = optional(bool, true) - event_types = optional(list(string), []) - topic_id = optional(string) + enabled = optional(bool, true) + event_types = optional(list(string), []) + topic_id = optional(string) + kms_key_name = optional(string) })) vertical_pod_autoscaling = optional(bool, false) workload_identity = optional(bool, true) diff --git a/modules/logging-bucket/README.md b/modules/logging-bucket/README.md index 6eb5bf579..c8ad5d8d2 100644 --- a/modules/logging-bucket/README.md +++ b/modules/logging-bucket/README.md @@ -118,17 +118,17 @@ module "bucket" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L60) | Name of the logging bucket. | string | ✓ | | -| [parent](variables.tf#L65) | ID of the parent resource containing the bucket in the format 'project_id' 'folders/folder_id', 'organizations/organization_id' or 'billing_account_id'. | string | ✓ | | -| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} | -| [description](variables.tf#L31) | Human-readable description for the logging bucket. | string | | null | -| [kms_key_name](variables.tf#L37) | To enable CMEK for a project logging bucket, set this field to a valid name. The associated service account requires cloudkms.cryptoKeyEncrypterDecrypter roles assigned for the key. | string | | null | -| [location](variables.tf#L43) | Location of the bucket. | string | | "global" | -| [log_analytics](variables.tf#L49) | Enable and configure Analytics Log. | object({…}) | | {} | -| [parent_type](variables.tf#L73) | Parent object type for the bucket (project, folder, organization, billing_account). | string | | "project" | -| [retention](variables.tf#L80) | Retention time in days for the logging bucket. | number | | 30 | -| [tag_bindings](variables.tf#L86) | Tag bindings for this bucket, in key => tag value id format. | map(string) | | {} | -| [views](variables.tf#L93) | Log views for this bucket. | map(object({…})) | | {} | +| [name](variables.tf#L61) | Name of the logging bucket. | string | ✓ | | +| [parent](variables.tf#L66) | ID of the parent resource containing the bucket in the format 'project_id' 'folders/folder_id', 'organizations/organization_id' or 'billing_account_id'. | string | ✓ | | +| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} | +| [description](variables.tf#L32) | Human-readable description for the logging bucket. | string | | null | +| [kms_key_name](variables.tf#L38) | To enable CMEK for a project logging bucket, set this field to a valid name. The associated service account requires cloudkms.cryptoKeyEncrypterDecrypter roles assigned for the key. | string | | null | +| [location](variables.tf#L44) | Location of the bucket. | string | | "global" | +| [log_analytics](variables.tf#L50) | Enable and configure Analytics Log. | object({…}) | | {} | +| [parent_type](variables.tf#L74) | Parent object type for the bucket (project, folder, organization, billing_account). | string | | "project" | +| [retention](variables.tf#L81) | Retention time in days for the logging bucket. | number | | 30 | +| [tag_bindings](variables.tf#L87) | Tag bindings for this bucket, in key => tag value id format. | map(string) | | {} | +| [views](variables.tf#L94) | Log views for this bucket. | map(object({…})) | | {} | ## Outputs diff --git a/modules/logging-bucket/main.tf b/modules/logging-bucket/main.tf index 65178511c..c5f2bca6c 100644 --- a/modules/logging-bucket/main.tf +++ b/modules/logging-bucket/main.tf @@ -42,6 +42,7 @@ locals { } } + resource "google_logging_project_bucket_config" "bucket" { count = var.parent_type == "project" ? 1 : 0 project = local.parent_id @@ -53,7 +54,7 @@ resource "google_logging_project_bucket_config" "bucket" { dynamic "cmek_settings" { for_each = var.kms_key_name == null ? [] : [""] content { - kms_key_name = var.kms_key_name + kms_key_name = lookup(local.ctx.kms_keys, var.kms_key_name, var.kms_key_name) } } } diff --git a/modules/logging-bucket/variables.tf b/modules/logging-bucket/variables.tf index 644412c95..c5938c818 100644 --- a/modules/logging-bucket/variables.tf +++ b/modules/logging-bucket/variables.tf @@ -20,6 +20,7 @@ variable "context" { custom_roles = optional(map(string), {}) folder_ids = optional(map(string), {}) iam_principals = optional(map(string), {}) + kms_keys = optional(map(string), {}) locations = optional(map(string), {}) project_ids = optional(map(string), {}) tag_values = optional(map(string), {}) diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md index 50eb6a78c..685cba01a 100644 --- a/modules/project-factory/README.md +++ b/modules/project-factory/README.md @@ -809,7 +809,7 @@ compute.disableSerialPortAccess: | [data_overrides](variables.tf#L122) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} | | [folders](variables-folders.tf#L17) | Folders data merged with factory data. | map(object({…})) | | {} | | [notification_channels](variables-billing.tf#L17) | Notification channels used by budget alerts. | map(object({…})) | | {} | -| [projects](variables-projects.tf#L17) | Projects data merged with factory data. | map(object({…})) | | {} | +| [projects](variables-projects.tf#L17) | Projects data merged with factory data. | map(object({…})) | | {} | ## Outputs diff --git a/modules/project-factory/projects-bigquery.tf b/modules/project-factory/projects-bigquery.tf index 93a758020..eb4d8dfc3 100644 --- a/modules/project-factory/projects-bigquery.tf +++ b/modules/project-factory/projects-bigquery.tf @@ -18,11 +18,12 @@ locals { projects_bigquery_datasets = flatten([ for k, v in local.projects_input : [ for name, opts in lookup(v, "datasets", {}) : { - project_key = k - project_name = v.name - id = name - friendly_name = lookup(opts, "friendly_name", null) - location = lookup(opts, "location", null) + project_key = k + project_name = v.name + id = name + encryption_key = lookup(opts, "encryption_key", null) + friendly_name = lookup(opts, "friendly_name", null) + location = lookup(opts, "location", null) } ] ]) @@ -33,7 +34,7 @@ module "bigquery-datasets" { for_each = { for k in local.projects_bigquery_datasets : "${k.project_key}/${k.id}" => k } - project_id = module.projects[each.value.project_key].project_id + project_id = module.projects-iam[each.value.project_key].project_id id = each.value.id context = merge(local.ctx, { iam_principals = merge( @@ -46,7 +47,8 @@ module "bigquery-datasets" { locations = local.ctx.locations project_ids = local.ctx_project_ids }) - friendly_name = each.value.friendly_name + encryption_key = each.value.encryption_key + friendly_name = each.value.friendly_name location = coalesce( local.data_defaults.overrides.locations.bigquery, lookup(each.value, "location", null), diff --git a/modules/project-factory/projects-buckets.tf b/modules/project-factory/projects-buckets.tf index a2aea7ac1..4e9d0fa64 100644 --- a/modules/project-factory/projects-buckets.tf +++ b/modules/project-factory/projects-buckets.tf @@ -62,7 +62,7 @@ module "buckets" { for_each = { for k in local.projects_buckets : "${k.project_key}/${k.name}" => k } - project_id = module.projects[each.value.project_key].project_id + project_id = module.projects-iam[each.value.project_key].project_id prefix = each.value.prefix name = "${each.value.project_name}-${each.value.name}" bucket_create = each.value.create diff --git a/modules/project-factory/variables-projects.tf b/modules/project-factory/variables-projects.tf index ac3287514..d9901142c 100644 --- a/modules/project-factory/variables-projects.tf +++ b/modules/project-factory/variables-projects.tf @@ -154,8 +154,9 @@ variable "projects" { })), {}) contacts = optional(map(list(string)), {}) datasets = optional(map(object({ - friendly_name = optional(string) - location = optional(string) + encryption_key = optional(string) + friendly_name = optional(string) + location = optional(string) })), {}) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ diff --git a/modules/project/cmek.tf b/modules/project/cmek.tf index ef71119a8..3a3efbbf1 100644 --- a/modules/project/cmek.tf +++ b/modules/project/cmek.tf @@ -31,7 +31,7 @@ locals { # https://cloud.google.com/composer/docs/composer-3/configure-cmek-encryption#grant-roles-permissions "composer.googleapis.com" : ["composer", "storage"] "compute.googleapis.com" : ["compute"] - "container.googleapis.com" : ["compute"] + "container.googleapis.com" : ["compute", "container-engine-robot"] "dataflow.googleapis.com" : ["dataflow", "compute"] "dataform.googleapis.com" : ["dataform"] "datafusion.googleapis.com" : [ @@ -42,12 +42,13 @@ locals { "datastream.googleapis.com" : ["datastream"] "dialogflow.googleapis.com" : ["dialogflow-cmek"] "file.googleapis.com" : ["cloud-filer"] + "logging.googleapis.com" : ["logging"] "pubsub.googleapis.com" : ["pubsub"] + "run.googleapis.com" : ["cloudrun"] "secretmanager.googleapis.com" : ["secretmanager"] "spanner.googleapis.com" : ["spanner"] "sqladmin.googleapis.com" : ["cloud-sql"] "storage.googleapis.com" : ["storage"] - "run.googleapis.com" : ["cloudrun"] } _all_cmek_bindings = flatten([ for service, keys in var.service_encryption_key_ids : [ diff --git a/tests/modules/bigquery_dataset/context.tfvars b/tests/modules/bigquery_dataset/context.tfvars index b4805a158..de038c230 100644 --- a/tests/modules/bigquery_dataset/context.tfvars +++ b/tests/modules/bigquery_dataset/context.tfvars @@ -11,6 +11,9 @@ context = { myuser = "user:test-user@example.com" myuser2 = "user:test-user2@example.com" } + kms_keys = { + mykey = "projects/366118655033/locations/europe-west8/keyRings/mykeyring/cryptoKeys/mykey" + } locations = { ew8 = "europe-west8" } @@ -21,9 +24,10 @@ context = { "test/one" = "tagValues/1234567890" } } -project_id = "$project_ids:test" -id = "dataset_0" -location = "$locations:ew8" +project_id = "$project_ids:test" +id = "dataset_0" +location = "$locations:ew8" +encryption_key = "$kms_keys:mykey" iam = { "$custom_roles:myrole_one" = [ "$iam_principals:myuser" diff --git a/tests/modules/bigquery_dataset/context.yaml b/tests/modules/bigquery_dataset/context.yaml index a9f3d17f0..ef273fb32 100644 --- a/tests/modules/bigquery_dataset/context.yaml +++ b/tests/modules/bigquery_dataset/context.yaml @@ -15,7 +15,8 @@ values: google_bigquery_dataset.default: dataset_id: dataset_0 - default_encryption_configuration: [] + default_encryption_configuration: + - kms_key_name: projects/366118655033/locations/europe-west8/keyRings/mykeyring/cryptoKeys/mykey default_partition_expiration_ms: null default_table_expiration_ms: null delete_contents_on_destroy: false diff --git a/tests/modules/gke_cluster_autopilot/examples/notifications.yaml b/tests/modules/gke_cluster_autopilot/examples/notifications.yaml new file mode 100644 index 000000000..7e2e4ad7e --- /dev/null +++ b/tests/modules/gke_cluster_autopilot/examples/notifications.yaml @@ -0,0 +1,48 @@ +# Copyright 2023 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. + +values: + module.cluster-1.google_container_cluster.cluster: + notification_config: + - pubsub: + - enabled: true + filter: + - event_type: + - SECURITY_BULLETIN_EVENT + - UPGRADE_EVENT + + module.cluster-1.google_pubsub_topic.notifications[0]: + effective_labels: + content: gke-notifications + goog-terraform-provisioned: 'true' + ingestion_data_source_settings: [] + kms_key_name: projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey + labels: + content: gke-notifications + message_retention_duration: null + message_transforms: [] + name: gke-pubsub-notifications + project: project-id + schema_settings: [] + tags: null + terraform_labels: + content: gke-notifications + goog-terraform-provisioned: 'true' + timeouts: null + +counts: + google_container_cluster: 1 + google_pubsub_topic: 1 + modules: 1 + resources: 2 diff --git a/tests/modules/gke_cluster_standard/examples/notifications.yaml b/tests/modules/gke_cluster_standard/examples/notifications.yaml index 20d3fc887..901cebdd5 100644 --- a/tests/modules/gke_cluster_standard/examples/notifications.yaml +++ b/tests/modules/gke_cluster_standard/examples/notifications.yaml @@ -160,7 +160,7 @@ values: content: gke-notifications goog-terraform-provisioned: 'true' ingestion_data_source_settings: [] - kms_key_name: null + kms_key_name: projects/myproject/locations/global/keyRings/mykeyring/cryptoKeys/mykey labels: content: gke-notifications message_retention_duration: null diff --git a/tests/modules/logging_bucket/context.tfvars b/tests/modules/logging_bucket/context.tfvars index 878f26374..ada9dfb84 100644 --- a/tests/modules/logging_bucket/context.tfvars +++ b/tests/modules/logging_bucket/context.tfvars @@ -11,6 +11,9 @@ context = { myuser = "user:test-user@example.com" myuser2 = "user:test-user2@example.com" } + kms_keys = { + mykey = "projects/366118655033/locations/europe-west8/keyRings/mykeyring/cryptoKeys/mykey" + } locations = { ew8 = "europe-west8" } @@ -21,9 +24,10 @@ context = { "test/one" = "tagValues/1234567890" } } -name = "mybucket" -location = "$locations:ew8" -parent = "$project_ids:myproject" +kms_key_name = "$kms_keys:mykey" +name = "mybucket" +location = "$locations:ew8" +parent = "$project_ids:myproject" tag_bindings = { foo = "$tag_values:test/one" } diff --git a/tests/modules/logging_bucket/context.yaml b/tests/modules/logging_bucket/context.yaml index 6932406e3..147b4a851 100644 --- a/tests/modules/logging_bucket/context.yaml +++ b/tests/modules/logging_bucket/context.yaml @@ -35,7 +35,8 @@ values: role: roles/viewer google_logging_project_bucket_config.bucket[0]: bucket_id: mybucket - cmek_settings: [] + cmek_settings: + - kms_key_name: projects/366118655033/locations/europe-west8/keyRings/mykeyring/cryptoKeys/mykey enable_analytics: false index_configs: [] location: europe-west8