diff --git a/modules/cloudsql-instance/README.md b/modules/cloudsql-instance/README.md index ab66fc2c1..8b2e9ffc7 100644 --- a/modules/cloudsql-instance/README.md +++ b/modules/cloudsql-instance/README.md @@ -413,7 +413,7 @@ module "db" { | [network_config](variables.tf#L184) | Network configuration for the instance. Only one between private_network and psc_config can be used. | object({…}) | ✓ | | | [project_id](variables.tf#L231) | The ID of the project where this instances will be created. | string | ✓ | | | [region](variables.tf#L236) | Region of the primary instance. | string | ✓ | | -| [tier](variables.tf#L287) | The machine type to use for the instances. | string | ✓ | | +| [tier](variables.tf#L288) | The machine type to use for the instances. | string | ✓ | | | [activation_policy](variables.tf#L16) | This variable specifies when the instance should be active. Can be either ALWAYS, NEVER or ON_DEMAND. Default is ALWAYS. | string | | "ALWAYS" | | [availability_type](variables.tf#L27) | Availability type for the primary replica. Either `ZONAL` or `REGIONAL`. | string | | "ZONAL" | | [backup_configuration](variables.tf#L33) | Backup settings for primary instance. Will be automatically enabled if using MySQL with one or more replicas. | object({…}) | | {…} | @@ -433,12 +433,12 @@ module "db" { | [maintenance_config](variables.tf#L146) | Set maintenance window configuration and maintenance deny period (up to 90 days). Date format: 'yyyy-mm-dd'. | object({…}) | | {} | | [password_validation_policy](variables.tf#L207) | Password validation policy configuration for instances. | object({…}) | | null | | [prefix](variables.tf#L221) | Optional prefix used to generate instance names. | string | | null | -| [replicas](variables.tf#L241) | Map of NAME=> {REGION, KMS_KEY} for additional read replicas. Set to null to disable replica creation. | map(object({…})) | | {} | -| [root_password](variables.tf#L251) | Root password of the Cloud SQL instance, or flag to create a random password. Required for MS SQL Server. | object({…}) | | {} | -| [ssl](variables.tf#L265) | Setting to enable SSL, set config and certificates. | object({…}) | | {} | -| [terraform_deletion_protection](variables.tf#L280) | Prevent terraform from deleting instances. | bool | | true | -| [time_zone](variables.tf#L292) | The time_zone to be used by the database engine (supported only for SQL Server), in SQL Server timezone format. | string | | null | -| [users](variables.tf#L298) | Map of users to create in the primary instance (and replicated to other replicas). For MySQL, anything after the first `@` (if present) will be used as the user's host. Set PASSWORD to null if you want to get an autogenerated password. The user types available are: 'BUILT_IN', 'CLOUD_IAM_USER' or 'CLOUD_IAM_SERVICE_ACCOUNT'. | map(object({…})) | | {} | +| [replicas](variables.tf#L241) | Map of NAME=> {REGION, KMS_KEY, AVAILABILITY_TYPE} for additional read replicas. Set to null to disable replica creation. | map(object({…})) | | {} | +| [root_password](variables.tf#L252) | Root password of the Cloud SQL instance, or flag to create a random password. Required for MS SQL Server. | object({…}) | | {} | +| [ssl](variables.tf#L266) | Setting to enable SSL, set config and certificates. | object({…}) | | {} | +| [terraform_deletion_protection](variables.tf#L281) | Prevent terraform from deleting instances. | bool | | true | +| [time_zone](variables.tf#L293) | The time_zone to be used by the database engine (supported only for SQL Server), in SQL Server timezone format. | string | | null | +| [users](variables.tf#L299) | Map of users to create in the primary instance (and replicated to other replicas). For MySQL, anything after the first `@` (if present) will be used as the user's host. Set PASSWORD to null if you want to get an autogenerated password. The user types available are: 'BUILT_IN', 'CLOUD_IAM_USER' or 'CLOUD_IAM_SERVICE_ACCOUNT'. | map(object({…})) | | {} | ## Outputs diff --git a/modules/cloudsql-instance/main.tf b/modules/cloudsql-instance/main.tf index cafe9b56e..663d1172e 100644 --- a/modules/cloudsql-instance/main.tf +++ b/modules/cloudsql-instance/main.tf @@ -215,12 +215,12 @@ resource "google_sql_database_instance" "replicas" { disk_autoresize_limit = var.disk_autoresize_limit disk_size = var.disk_size disk_type = var.disk_type - # availability_type = var.availability_type - user_labels = var.labels - activation_policy = var.activation_policy - collation = var.collation - connector_enforcement = var.connector_enforcement - time_zone = var.time_zone + availability_type = each.value.availability_type + user_labels = var.labels + activation_policy = var.activation_policy + collation = var.collation + connector_enforcement = var.connector_enforcement + time_zone = var.time_zone ip_configuration { diff --git a/modules/cloudsql-instance/variables.tf b/modules/cloudsql-instance/variables.tf index 72a4fa5da..b566426d9 100644 --- a/modules/cloudsql-instance/variables.tf +++ b/modules/cloudsql-instance/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -239,10 +239,11 @@ variable "region" { } variable "replicas" { - description = "Map of NAME=> {REGION, KMS_KEY} for additional read replicas. Set to null to disable replica creation." + description = "Map of NAME=> {REGION, KMS_KEY, AVAILABILITY_TYPE} for additional read replicas. Set to null to disable replica creation." type = map(object({ region = string encryption_key_name = optional(string) + availability_type = optional(string) })) default = {} nullable = false diff --git a/modules/net-firewall-policy/README.md b/modules/net-firewall-policy/README.md index ac02f48b7..9f76a1013 100644 --- a/modules/net-firewall-policy/README.md +++ b/modules/net-firewall-policy/README.md @@ -15,6 +15,11 @@ The module also makes fewer assumptions about implicit defaults, only using one - [Global Network policy](#global-network-policy) - [Regional Network policy](#regional-network-policy) - [Factory](#factory) + - [Firewall Rule Factory Schema](#firewall-rule-factory-schema) + - [Dynamic Rule Matching](#dynamic-rule-matching) + - [Ingress Rules (](#ingress-rules-) + - [Egress Rules (](#egress-rules-) + - [Rule-Level Mappings](#rule-level-mappings) - [Variables](#variables) - [Outputs](#outputs) @@ -174,6 +179,7 @@ Factory configuration is via three optional attributes in the `rules_factory_con - `ingress_rules_file_path` specifying the path to the ingress rules file Factory rules are merged with rules declared in code, with the latter taking precedence where both use the same key. +Also, the factory applies implicit defaults: `action` defaults to `deny` for egress and `allow` for ingress, while omitting `layer4_configs` makes the rule match all protocols. This is an example of a simple factory: @@ -309,7 +315,71 @@ http: ports: - 80 ``` + +#### Firewall Rule Factory Schema + +The following schema outlines all available fields for defining a rule within a factory YAML file. Use this as a reference, and note the inline comments for fields that apply only to specific policy types. + +```yaml +rule-name: + priority: + action: + description: + disabled: + enable_logging: + security_profile_group: # Not for Regional policies + target_service_accounts: [] + target_tags: [] # Not for Hierarchical policies + target_resources: [] # For Hierarchical policies only + tls_inspect: # Not for Regional policies + match: + source_ranges: [] + destination_ranges: [] + source_tags: [] # Not for Hierarchical policies + threat_intelligences: [] + fqdns: [] + address_groups: [] + region_codes: [] + layer4_configs: + - protocol: + ports: [] +``` + +### Dynamic Rule Matching + +This module simplifies firewall rule creation by using generic, context-aware variables within the `match` block. Based on the rule's specified `direction` (`INGRESS` or `EGRESS`), the module maps these generic variables to the correct source- (`src_*`) or destination-specific (`dest_*`) arguments in the underlying resource. + +The tables below provide a complete reference for these dynamic mappings. + +#### Ingress Rules (`direction = "INGRESS"`) + +| Module Variable (`match.*`) | Mapped Resource Attribute | +| :--- | :--- | +| `address_groups` | `src_address_groups` | +| `fqdns` | `src_fqdns` | +| `region_codes` | `src_region_codes` | +| `source_tags` | `src_secure_tags` | +| `threat_intelligences` | `src_threat_intelligences` | + +#### Egress Rules (`direction = "EGRESS"`) + +| Module Variable (`match.*`) | Mapped Resource Attribute | +| :--- | :--- | +| `address_groups` | `dest_address_groups` | +| `fqdns` | `dest_fqdns` | +| `region_codes` | `dest_region_codes` | +| `threat_intelligences` | `dest_threat_intelligences` | + +#### Rule-Level Mappings + +The following variable is defined at the top level of the rule (not within the `match` block) and is mapped directly, regardless of the rule's direction. + +| Module Variable | Mapped Resource Attribute | +| :--- | :--- | +| `target_tags` | `target_secure_tags` | + + ## Variables | name | description | type | required | default | diff --git a/modules/project/cmek.tf b/modules/project/cmek.tf index 0d369d2c4..50b954aec 100644 --- a/modules/project/cmek.tf +++ b/modules/project/cmek.tf @@ -1,5 +1,5 @@ /** - * Copyright 2024 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ locals { "artifactregistry.googleapis.com" : ["artifactregistry"] "bigtableadmin.googleapis.com" : ["bigtable"] "bigquery.googleapis.com" : ["bigquery-encryption"] - # the list for composer now track composer 3 + # the list for composer now tracks composer 3 # https://cloud.google.com/composer/docs/composer-3/configure-cmek-encryption#grant-roles-permissions "composer.googleapis.com" : ["composer", "storage"] "compute.googleapis.com" : ["compute"] @@ -49,20 +49,28 @@ locals { "storage.googleapis.com" : ["storage"] "run.googleapis.com" : ["cloudrun"] } - _cmek_members = merge(flatten([ + _all_cmek_bindings = flatten([ for service, keys in var.service_encryption_key_ids : [ - # use the deps listed above, if the service does not appear - # there, use all the service agents belonging to the service - for dep in try(local._cmek_agents_by_service[service], [for x in local._service_agents_by_api[service] : x.name], [service]) : { - # use index in map key, to allow specifying keys, that will be created in the same apply - for index, key in keys : - "key-${index}.${local._aliased_service_agents[dep].name}" => { - key = key - agent = local._aliased_service_agents[dep].iam_email + for dep in try(local._cmek_agents_by_service[service], [for x in local._service_agents_by_api[service] : x.name], [service]) : [ + for key in keys : { + key_id = key + agent_name = local._aliased_service_agents[dep].name + agent_email = local._aliased_service_agents[dep].iam_email } - } + ] ] - ])...) + ]) + _cmek_bindings_grouped_by_agent = { + for binding in local._all_cmek_bindings : binding.agent_name => binding... + } + _cmek_members = merge([ + for agent_name, bindings in local._cmek_bindings_grouped_by_agent : { + for i, binding in bindings : "key-${i}.${agent_name}" => { + key = binding.key_id + agent = binding.agent_email + } + } + ]...) } resource "google_kms_crypto_key_iam_member" "service_agent_cmek" {