diff --git a/blueprints/apigee/bigquery-analytics/main.tf b/blueprints/apigee/bigquery-analytics/main.tf index d1534ad77..51f9a13f2 100644 --- a/blueprints/apigee/bigquery-analytics/main.tf +++ b/blueprints/apigee/bigquery-analytics/main.tf @@ -143,6 +143,7 @@ module "bucket_export" { ] } notification_config = { + create_topic = {} enabled = true payload_format = "JSON_API_V1" sa_email = module.project.service_agents.storage.email diff --git a/blueprints/data-solutions/vertex-mlops/README.md b/blueprints/data-solutions/vertex-mlops/README.md index 66ae67567..9caaf0727 100644 --- a/blueprints/data-solutions/vertex-mlops/README.md +++ b/blueprints/data-solutions/vertex-mlops/README.md @@ -79,20 +79,21 @@ module "test" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [notebooks](variables.tf#L76) | Vertex AI workbenches to be deployed. Service Account runtime/instances deployed. | map(object({…})) | ✓ | | -| [project_config](variables.tf#L103) | Provide 'billing_account_id' value if project creation is needed, uses existing 'project_id' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | ✓ | | +| [notebooks](variables.tf#L82) | Vertex AI workbenches to be deployed. Service Account runtime/instances deployed. | map(object({…})) | ✓ | | +| [project_config](variables.tf#L109) | Provide 'billing_account_id' value if project creation is needed, uses existing 'project_id' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…}) | ✓ | | | [bucket_name](variables.tf#L18) | GCS bucket name to store the Vertex AI artifacts. | string | | null | | [dataset_name](variables.tf#L24) | BigQuery Dataset to store the training data. | string | | null | | [deletion_protection](variables.tf#L30) | Prevent Terraform from destroying data storage resources (storage buckets, GKE clusters, CloudSQL instances) in this blueprint. When this field is set in Terraform state, a terraform destroy or terraform apply that would delete data storage resources will fail. | bool | | false | | [groups](variables.tf#L37) | Name of the groups (name@domain.org) to apply opinionated IAM permissions. | object({…}) | | {} | -| [identity_pool_claims](variables.tf#L48) | Claims to be used by Workload Identity Federation (i.e.: attribute.repository/ORGANIZATION/REPO). If a not null value is provided, then google_iam_workload_identity_pool resource will be created. | string | | null | -| [labels](variables.tf#L54) | Labels to be assigned at project level. | map(string) | | {} | -| [location](variables.tf#L60) | Location used for multi-regional resources. | string | | "eu" | -| [network_config](variables.tf#L66) | Shared VPC network configurations to use. If null networks will be created in projects with preconfigured values. | object({…}) | | null | -| [prefix](variables.tf#L97) | Prefix used for the project id. | string | | null | -| [region](variables.tf#L117) | Region used for regional resources. | string | | "europe-west4" | -| [repo_name](variables.tf#L123) | Cloud Source Repository name. null to avoid to create it. | string | | null | -| [service_encryption_keys](variables.tf#L129) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | {} | +| [identity_pool_assertions](variables.tf#L48) | Assertions to be used by Workload Identityf Federation on tokens, for example: assertion.repository_owner=='ORGANIZATION'. | string | | null | +| [identity_pool_claims](variables.tf#L54) | Claims to be used by Workload Identity Federation (i.e.: attribute.repository/ORGANIZATION/REPO). If a not null value is provided, then google_iam_workload_identity_pool resource will be created. | string | | null | +| [labels](variables.tf#L60) | Labels to be assigned at project level. | map(string) | | {} | +| [location](variables.tf#L66) | Location used for multi-regional resources. | string | | "eu" | +| [network_config](variables.tf#L72) | Shared VPC network configurations to use. If null networks will be created in projects with preconfigured values. | object({…}) | | null | +| [prefix](variables.tf#L103) | Prefix used for the project id. | string | | null | +| [region](variables.tf#L123) | Region used for regional resources. | string | | "europe-west4" | +| [repo_name](variables.tf#L129) | Cloud Source Repository name. null to avoid to create it. | string | | null | +| [service_encryption_keys](variables.tf#L135) | Cloud KMS to use to encrypt different services. Key location should match service region. | object({…}) | | {} | ## Outputs @@ -111,9 +112,10 @@ module "test" { "env" = "dev", "team" = "ml" } - bucket_name = "gcs-test" - dataset_name = "bq_test" - identity_pool_claims = "attribute.repository/ORGANIZATION/REPO" + bucket_name = "gcs-test" + dataset_name = "bq_test" + identity_pool_assertions = "assertion.repository_owner=='ORGANIZATION'" + identity_pool_claims = "attribute.repository/ORGANIZATION/REPO" notebooks = { "myworkbench" = { type = "USER_MANAGED" diff --git a/blueprints/data-solutions/vertex-mlops/ci-cd.tf b/blueprints/data-solutions/vertex-mlops/ci-cd.tf index e5e728672..84f72087d 100644 --- a/blueprints/data-solutions/vertex-mlops/ci-cd.tf +++ b/blueprints/data-solutions/vertex-mlops/ci-cd.tf @@ -33,6 +33,7 @@ resource "google_iam_workload_identity_pool_provider" "github_provider" { "google.subject" = "assertion.sub" "attribute.repository" = "assertion.repository" } + attribute_condition = var.identity_pool_assertions oidc { issuer_uri = "https://token.actions.githubusercontent.com" } diff --git a/blueprints/data-solutions/vertex-mlops/variables.tf b/blueprints/data-solutions/vertex-mlops/variables.tf index f27318751..2819ca798 100644 --- a/blueprints/data-solutions/vertex-mlops/variables.tf +++ b/blueprints/data-solutions/vertex-mlops/variables.tf @@ -45,6 +45,12 @@ variable "groups" { nullable = false } +variable "identity_pool_assertions" { + description = "Assertions to be used by Workload Identityf Federation on tokens, for example: assertion.repository_owner=='ORGANIZATION'." + type = string + default = null +} + variable "identity_pool_claims" { description = "Claims to be used by Workload Identity Federation (i.e.: attribute.repository/ORGANIZATION/REPO). If a not null value is provided, then google_iam_workload_identity_pool resource will be created." type = string diff --git a/modules/gcs/README.md b/modules/gcs/README.md index 12a71ebf7..2964f73f8 100644 --- a/modules/gcs/README.md +++ b/modules/gcs/README.md @@ -311,7 +311,7 @@ module "bucket" { |---|---|:---:|:---:|:---:| | [location](variables.tf#L156) | Bucket location. | string | ✓ | | | [name](variables.tf#L199) | Bucket name suffix. | string | ✓ | | -| [project_id](variables.tf#L255) | Bucket project id. | string | ✓ | | +| [project_id](variables.tf#L257) | Bucket project id. | string | ✓ | | | [autoclass](variables.tf#L17) | Enable autoclass to automatically transition objects to appropriate storage classes based on their access pattern. If set to true, storage_class must be set to STANDARD. Defaults to false. | bool | | null | | [cors](variables.tf#L23) | CORS configuration for the bucket. Defaults to null. | object({…}) | | null | | [custom_placement_config](variables.tf#L34) | The bucket's custom location configuration, which specifies the individual regions that comprise a dual-region bucket. If the bucket is designated as REGIONAL or MULTI_REGIONAL, the parameters are empty. | list(string) | | null | @@ -326,19 +326,19 @@ module "bucket" { | [lifecycle_rules](variables.tf#L107) | Bucket lifecycle rule. | map(object({…})) | | {} | | [logging_config](variables.tf#L162) | Bucket logging configuration. | object({…}) | | null | | [managed_folders](variables.tf#L171) | Managed folders to create within the bucket in {PATH => CONFIG} format. | map(object({…})) | | {} | -| [notification_config](variables.tf#L204) | GCS Notification configuration. | object({…}) | | null | -| [objects_to_upload](variables.tf#L219) | Objects to be uploaded to bucket. | map(object({…})) | | {} | -| [prefix](variables.tf#L245) | Optional prefix used to generate the bucket name. | string | | null | -| [public_access_prevention](variables.tf#L260) | Prevents public access to the bucket. | string | | null | -| [requester_pays](variables.tf#L270) | Enables Requester Pays on a storage bucket. | bool | | null | -| [retention_policy](variables.tf#L276) | Bucket retention policy. | object({…}) | | null | -| [rpo](variables.tf#L285) | Bucket recovery point objective. | string | | null | -| [soft_delete_retention](variables.tf#L295) | The duration in seconds that soft-deleted objects in the bucket will be retained and cannot be permanently deleted. Set to 0 to override the default and disable. | number | | null | -| [storage_class](variables.tf#L301) | Bucket storage class. | string | | "STANDARD" | -| [tag_bindings](variables.tf#L311) | Tag bindings for this folder, in key => tag value id format. | map(string) | | {} | -| [uniform_bucket_level_access](variables.tf#L318) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool | | true | -| [versioning](variables.tf#L324) | Enable versioning, defaults to false. | bool | | null | -| [website](variables.tf#L330) | Bucket website. | object({…}) | | null | +| [notification_config](variables.tf#L204) | GCS Notification configuration. | object({…}) | | null | +| [objects_to_upload](variables.tf#L221) | Objects to be uploaded to bucket. | map(object({…})) | | {} | +| [prefix](variables.tf#L247) | Optional prefix used to generate the bucket name. | string | | null | +| [public_access_prevention](variables.tf#L262) | Prevents public access to the bucket. | string | | null | +| [requester_pays](variables.tf#L272) | Enables Requester Pays on a storage bucket. | bool | | null | +| [retention_policy](variables.tf#L278) | Bucket retention policy. | object({…}) | | null | +| [rpo](variables.tf#L287) | Bucket recovery point objective. | string | | null | +| [soft_delete_retention](variables.tf#L297) | The duration in seconds that soft-deleted objects in the bucket will be retained and cannot be permanently deleted. Set to 0 to override the default and disable. | number | | null | +| [storage_class](variables.tf#L303) | Bucket storage class. | string | | "STANDARD" | +| [tag_bindings](variables.tf#L313) | Tag bindings for this folder, in key => tag value id format. | map(string) | | {} | +| [uniform_bucket_level_access](variables.tf#L320) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool | | true | +| [versioning](variables.tf#L326) | Enable versioning, defaults to false. | bool | | null | +| [website](variables.tf#L332) | Bucket website. | object({…}) | | null | ## Outputs diff --git a/modules/gcs/main.tf b/modules/gcs/main.tf index aa4258a08..3c1a3ec6b 100644 --- a/modules/gcs/main.tf +++ b/modules/gcs/main.tf @@ -17,6 +17,7 @@ locals { prefix = var.prefix == null ? "" : "${var.prefix}-" notification = try(var.notification_config.enabled, false) + topic_create = try(var.notification_config.create_topic, null) != null } resource "google_storage_bucket" "bucket" { @@ -172,14 +173,15 @@ resource "google_storage_notification" "notification" { } resource "google_pubsub_topic_iam_binding" "binding" { - count = try(var.notification_config.create_topic, null) == true ? 1 : 0 + count = local.topic_create ? 1 : 0 topic = google_pubsub_topic.topic[0].id role = "roles/pubsub.publisher" members = ["serviceAccount:${var.notification_config.sa_email}"] } resource "google_pubsub_topic" "topic" { - count = try(var.notification_config.create_topic, null) == true ? 1 : 0 - project = var.project_id - name = var.notification_config.topic_name + count = local.topic_create ? 1 : 0 + project = var.project_id + name = var.notification_config.topic_name + kms_key_name = try(var.notification_config.topic_create.kms_key_id, null) } diff --git a/modules/gcs/variables.tf b/modules/gcs/variables.tf index 49d9fb202..2c81dd169 100644 --- a/modules/gcs/variables.tf +++ b/modules/gcs/variables.tf @@ -204,11 +204,13 @@ variable "name" { variable "notification_config" { description = "GCS Notification configuration." type = object({ - enabled = bool - payload_format = string - topic_name = string - sa_email = string - create_topic = optional(bool, true) + enabled = bool + payload_format = string + sa_email = string + topic_name = string + create_topic = optional(object({ + kms_key_id = optional(string) + })) event_types = optional(list(string)) custom_attributes = optional(map(string)) object_name_prefix = optional(string) diff --git a/modules/spanner-instance/main.tf b/modules/spanner-instance/main.tf index d35589ec1..26a8e3354 100644 --- a/modules/spanner-instance/main.tf +++ b/modules/spanner-instance/main.tf @@ -15,15 +15,21 @@ */ locals { - spanner_instance = var.instance_create ? google_spanner_instance.spanner_instance[0] : data.google_spanner_instance.spanner_instance[0] + spanner_instance = ( + var.instance_create + ? google_spanner_instance.spanner_instance[0] + : data.google_spanner_instance.spanner_instance[0] + ) } resource "google_spanner_instance_config" "spanner_instance_config" { - count = try(var.instance.config.auto_create, null) == null ? 0 : 1 - name = var.instance.config.name - project = var.project_id - display_name = coalesce(var.instance.config.auto_create.display_name, var.instance.config.name) - base_config = var.instance.config.auto_create.base_config + count = try(var.instance.config.auto_create, null) == null ? 0 : 1 + name = var.instance.config.name + project = var.project_id + display_name = coalesce( + var.instance.config.auto_create.display_name, var.instance.config.name + ) + base_config = var.instance.config.auto_create.base_config dynamic "replicas" { for_each = var.instance.config.auto_create.replicas content { @@ -42,9 +48,13 @@ data "google_spanner_instance" "spanner_instance" { } resource "google_spanner_instance" "spanner_instance" { - count = var.instance_create ? 1 : 0 - project = var.project_id - config = var.instance.config.auto_create == null ? var.instance.config.name : google_spanner_instance_config.spanner_instance_config[0].name + count = var.instance_create ? 1 : 0 + project = var.project_id + config = ( + var.instance.config.auto_create == null + ? var.instance.config.name + : google_spanner_instance_config.spanner_instance_config[0].name + ) name = var.instance.name display_name = coalesce(var.instance.display_name, var.instance.name) num_nodes = var.instance.num_nodes @@ -64,8 +74,12 @@ resource "google_spanner_instance" "spanner_instance" { dynamic "autoscaling_targets" { for_each = var.instance.autoscaling.targets == null ? [] : [""] content { - high_priority_cpu_utilization_percent = var.instance.autoscaling.targets.high_priority_cpu_utilization_percent - storage_utilization_percent = var.instance.autoscaling.targets.storage_utilization_percent + high_priority_cpu_utilization_percent = ( + var.instance.autoscaling.targets.high_priority_cpu_utilization_percent + ) + storage_utilization_percent = ( + var.instance.autoscaling.targets.storage_utilization_percent + ) } } }