From e45e8089ffa6e3c3a8e85904d86cbbdee04330a1 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Mon, 2 Mar 2026 09:32:13 +0100 Subject: [PATCH 1/3] comment alerting policy to prevent e2e errors (#3777) --- .../observability/iac-0/impersonation.yaml | 47 ++++++++++--------- tests/fast/stages/s0_org_setup/simple.yaml | 42 +---------------- 2 files changed, 25 insertions(+), 64 deletions(-) diff --git a/fast/stages/0-org-setup/datasets/classic/observability/iac-0/impersonation.yaml b/fast/stages/0-org-setup/datasets/classic/observability/iac-0/impersonation.yaml index a02f7ffad..0085e428c 100644 --- a/fast/stages/0-org-setup/datasets/classic/observability/iac-0/impersonation.yaml +++ b/fast/stages/0-org-setup/datasets/classic/observability/iac-0/impersonation.yaml @@ -38,26 +38,27 @@ logging_metrics: - key: email_id value_type: STRING -alerts: - sa-impersonation-alert: - display_name: Service Account Impersonation Alert - combiner: OR - conditions: - - display_name: Impersonation Detected - condition_threshold: - filter: | - metric.type="logging.googleapis.com/user/sa-impersonation" AND - resource.type="global" - comparison: COMPARISON_GT - threshold_value: 0 - duration: 60s - trigger: - count: 1 - aggregations: - - alignment_period: 60s - per_series_aligner: ALIGN_COUNT - cross_series_reducer: REDUCE_SUM - group_by_fields: ["metric.label.email_id"] - notification_channels: - - email-security - enabled: true +# TODO: this is commented to prevent lag in metric creation from breaking apply +# alerts: +# sa-impersonation-alert: +# display_name: Service Account Impersonation Alert +# combiner: OR +# conditions: +# - display_name: Impersonation Detected +# condition_threshold: +# filter: | +# metric.type="logging.googleapis.com/user/sa-impersonation" AND +# resource.type="global" +# comparison: COMPARISON_GT +# threshold_value: 0 +# duration: 60s +# trigger: +# count: 1 +# aggregations: +# - alignment_period: 60s +# per_series_aligner: ALIGN_COUNT +# cross_series_reducer: REDUCE_SUM +# group_by_fields: ["metric.label.email_id"] +# notification_channels: +# - email-security +# enabled: true diff --git a/tests/fast/stages/s0_org_setup/simple.yaml b/tests/fast/stages/s0_org_setup/simple.yaml index 16395beb7..682aea836 100644 --- a/tests/fast/stages/s0_org_setup/simple.yaml +++ b/tests/fast/stages/s0_org_setup/simple.yaml @@ -1284,45 +1284,6 @@ values: project: ft0-prod-iac-core-0 timeouts: null value_extractor: null - module.factory.module.projects["iac-0"].google_monitoring_alert_policy.alerts["sa-impersonation-alert"]: - alert_strategy: [] - combiner: OR - conditions: - - condition_absent: [] - condition_matched_log: [] - condition_monitoring_query_language: [] - condition_prometheus_query_language: [] - condition_sql: [] - condition_threshold: - - aggregations: - - alignment_period: 60s - cross_series_reducer: REDUCE_SUM - group_by_fields: - - metric.label.email_id - per_series_aligner: ALIGN_COUNT - comparison: COMPARISON_GT - denominator_aggregations: [] - denominator_filter: null - duration: 60s - evaluation_missing_data: null - filter: 'metric.type="logging.googleapis.com/user/sa-impersonation" AND - - resource.type="global" - - ' - forecast_options: [] - threshold_value: 0 - trigger: - - count: 1 - percent: null - display_name: Impersonation Detected - display_name: Service Account Impersonation Alert - documentation: [] - enabled: true - project: ft0-prod-iac-core-0 - severity: null - timeouts: null - user_labels: null module.factory.module.projects["iac-0"].google_monitoring_notification_channel.channels["email-security"]: description: null display_name: Security Team Email @@ -3019,7 +2980,6 @@ counts: google_logging_organization_sink: 3 google_logging_project_bucket_config: 3 google_logging_project_settings: 2 - google_monitoring_alert_policy: 1 google_monitoring_notification_channel: 1 google_org_policy_custom_constraint: 1 google_org_policy_policy: 37 @@ -3047,5 +3007,5 @@ counts: google_tags_tag_value_iam_binding: 4 local_file: 9 modules: 50 - resources: 328 + resources: 327 terraform_data: 4 From 0be09646b0eaf9c3f5e23744d61fcb16f3b673f2 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Wed, 4 Mar 2026 10:28:48 +0100 Subject: [PATCH 2/3] Add missing folder features to project factory and align logging across folder/org modules (#3779) --- CHANGELOG.md | 49 ++++++++- .../0-org-setup/schemas/folder.schema.json | 91 +++++++++++++++ .../2-networking/schemas/folder.schema.json | 91 +++++++++++++++ .../schemas/folder.schema.json | 91 +++++++++++++++ .../2-security/schemas/folder.schema.json | 91 +++++++++++++++ modules/folder/README.md | 24 ++-- modules/folder/logging.tf | 7 +- modules/folder/main.tf | 9 +- modules/folder/variables-logging.tf | 6 +- modules/folder/variables.tf | 3 + modules/organization/README.md | 16 +-- modules/organization/logging.tf | 6 +- modules/organization/variables-logging.tf | 1 - modules/organization/variables.tf | 1 + modules/project-factory/README.md | 2 +- modules/project-factory/folders.tf | 48 ++++++-- .../schemas/folder.schema.json | 91 +++++++++++++++ .../project-factory/schemas/folder.schema.md | 25 +++++ modules/project-factory/variables-folders.tf | 27 ++++- tests/modules/folder/context.tfvars | 6 + tests/modules/folder/context.yaml | 6 +- tests/modules/folder/main.tf | 104 ------------------ tests/modules/organization/context.tfvars | 4 + tests/modules/organization/context.yaml | 1 + 24 files changed, 651 insertions(+), 149 deletions(-) delete mode 100644 tests/modules/folder/main.tf diff --git a/CHANGELOG.md b/CHANGELOG.md index 974123e5c..fd19f2d1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,52 @@ All notable changes to this project will be documented in this file. -## [Unreleased] +## [Unreleased] + +### BREAKING CHANGES + +- `modules/kms`: they key for IAM authoritative and additive bindings has changed, reapply twice to preserve bindings after updating the module. [[#3775](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3775)] +- `modules/net-lb-app-int`: `neg_configs.cloudrun.target_service.tag` has been moved to `neg_configs.cloudrun.tag`, the old location is still supported but will be deprecated in the future. [[#3771](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3771)] +- `modules/gke-nodepool`: Disk configuration has moved to a new `node_config.boot_disk` block to align with upcoming provider changes. Support for the legacy flat attributes has been kept to ensure backward compatibility. [[#3767](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3767)] +- `modules/bigquery-dataset`: the resource names for IAM bindings have changed and will trigger recreation [[#3755](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3755)] + + +### FAST + +- [[#3765](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3765)] Fix support for credit types in billing module budgets ([ludoo](https://github.com/ludoo)) +- [[#3757](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3757)] Added custom prefix support for automation SA ([kovagoadam](https://github.com/kovagoadam)) +- [[#3755](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3755)] Support additional attributes for buckets/datasets in project factory module ([ludoo](https://github.com/ludoo)) +- [[#3747](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3747)] Fix network references in FAST gcve stage ([norbert-loderer](https://github.com/norbert-loderer)) +- [[#3742](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3742)] Fix vpc-sc role name ([wiktorn](https://github.com/wiktorn)) +- [[#3730](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3730)] Dataset configuration template for custom BGP advertisements on Cloud Router and BGP Peers ([SamuPert](https://github.com/SamuPert)) + +### MODULES + +- [[#3775](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3775)] Allow reusing IAM binding key across objects in kms module ([ludoo](https://github.com/ludoo)) +- [[#3776](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3776)] fix(net-lb-app-ext-regional): use list(string) for route_rules cors_policy attributes ([cvanwijck-hub24](https://github.com/cvanwijck-hub24)) +- [[#3771](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3771)] Allow specifying cloudrun target without service name in net-lb-app-int module ([ludoo](https://github.com/ludoo)) +- [[#3770](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3770)] Add support for regional health checks to net-lb-int module ([ludoo](https://github.com/ludoo)) +- [[#3767](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3767)] Support hyperdisk-balanced options on gke-nodepool module ([ludoo](https://github.com/ludoo)) +- [[#3766](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3766)] Support TLS settings in app load balancer modules ([ludoo](https://github.com/ludoo)) +- [[#3765](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3765)] Fix support for credit types in billing module budgets ([ludoo](https://github.com/ludoo)) +- [[#3761](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3761)] Add parameter to modules/pubsub to support message_storage_policy.enforce_in_transit ([lyricnz](https://github.com/lyricnz)) +- [[#3763](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3763)] Fixed psc connection id in net-address module output ([apichick](https://github.com/apichick)) +- [[#3759](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3759)] Bugfix/maintenance exclusion ([lyricnz](https://github.com/lyricnz)) +- [[#3757](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3757)] Added custom prefix support for automation SA ([kovagoadam](https://github.com/kovagoadam)) +- [[#3756](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3756)] Fix example for snapshot schedules ([wiktorn](https://github.com/wiktorn)) +- [[#3755](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3755)] Support additional attributes for buckets/datasets in project factory module ([ludoo](https://github.com/ludoo)) +- [[#3753](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3753)] Fix regional resource policy attachment in compute-vm module ([ludoo](https://github.com/ludoo)) +- [[#3752](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3752)] Fix project factory service agents outputs from iamEmail to iam_email ([LucaPrete](https://github.com/LucaPrete)) +- [[#3750](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3750)] [project-factory] Add service_agent outputs ([LucaPrete](https://github.com/LucaPrete)) +- [[#3749](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3749)] Bump ajv from 8.17.1 to 8.18.0 in /modules/api-gateway/recipe-multi-region/function ([dependabot[bot]](https://github.com/dependabot[bot])) +- [[#3746](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3746)] docs(organization): document external IAM management for logging sinks at scale ([mInrOz](https://github.com/mInrOz)) +- [[#3741](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3741)] Allow specifying "network_tier" for Compute Engine VM Templates ([hexa2k9](https://github.com/hexa2k9)) +- [[#3740](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3740)] Fix permadiff on E2E test ([wiktorn](https://github.com/wiktorn)) +- [[#3737](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3737)] Bump qs from 6.14.1 to 6.14.2 in /modules/api-gateway/recipe-multi-region/function ([dependabot[bot]](https://github.com/dependabot[bot])) + +### TOOLS + +- [[#3748](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/3748)] Refactor Github Action per b/485167538 ([google-admin](https://github.com/google-admin)) ## [53.0.0] - 2026-02-12 @@ -2314,4 +2359,4 @@ Project templates are still following the old project factory schemas, and will [32.0.1]: [32.0.0]: [31.1.0]: -[31.0.0]: +[31.0.0]: \ No newline at end of file diff --git a/fast/stages/0-org-setup/schemas/folder.schema.json b/fast/stages/0-org-setup/schemas/folder.schema.json index 393f49d0c..3150efbcd 100644 --- a/fast/stages/0-org-setup/schemas/folder.schema.json +++ b/fast/stages/0-org-setup/schemas/folder.schema.json @@ -4,6 +4,30 @@ "type": "object", "additionalProperties": false, "properties": { + "asset_search": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z0-9-]+$": { + "type": "object", + "additionalProperties": false, + "required": [ + "asset_types" + ], + "properties": { + "asset_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "query": { + "type": "string" + } + } + } + } + }, "asset_feeds": { "type": "object", "additionalProperties": false, @@ -236,6 +260,73 @@ "deletion_protection": { "type": "boolean" }, + "id": { + "type": "string", + "pattern": "^(folders/[0-9]+|\\$folder_ids:[a-z0-9_-]+)$" + }, + "firewall_policy": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "policy" + ], + "properties": { + "name": { + "type": "string" + }, + "policy": { + "type": "string" + } + } + }, + "logging": { + "type": "object", + "additionalProperties": false, + "properties": { + "kms_key_name": { + "type": "string" + }, + "storage_location": { + "type": "string" + }, + "sinks": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9-_]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "exclusions": { + "type": "object" + }, + "filter": { + "type": "string" + }, + "type": { + "type": "string", + "default": "logging", + "enum": [ + "bigquery", + "logging", + "project", + "pubsub", + "storage" + ] + } + } + } + } + } + } + }, "factories_config": { "type": "object", "additionalProperties": false, diff --git a/fast/stages/2-networking/schemas/folder.schema.json b/fast/stages/2-networking/schemas/folder.schema.json index 393f49d0c..3150efbcd 100644 --- a/fast/stages/2-networking/schemas/folder.schema.json +++ b/fast/stages/2-networking/schemas/folder.schema.json @@ -4,6 +4,30 @@ "type": "object", "additionalProperties": false, "properties": { + "asset_search": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z0-9-]+$": { + "type": "object", + "additionalProperties": false, + "required": [ + "asset_types" + ], + "properties": { + "asset_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "query": { + "type": "string" + } + } + } + } + }, "asset_feeds": { "type": "object", "additionalProperties": false, @@ -236,6 +260,73 @@ "deletion_protection": { "type": "boolean" }, + "id": { + "type": "string", + "pattern": "^(folders/[0-9]+|\\$folder_ids:[a-z0-9_-]+)$" + }, + "firewall_policy": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "policy" + ], + "properties": { + "name": { + "type": "string" + }, + "policy": { + "type": "string" + } + } + }, + "logging": { + "type": "object", + "additionalProperties": false, + "properties": { + "kms_key_name": { + "type": "string" + }, + "storage_location": { + "type": "string" + }, + "sinks": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9-_]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "exclusions": { + "type": "object" + }, + "filter": { + "type": "string" + }, + "type": { + "type": "string", + "default": "logging", + "enum": [ + "bigquery", + "logging", + "project", + "pubsub", + "storage" + ] + } + } + } + } + } + } + }, "factories_config": { "type": "object", "additionalProperties": false, diff --git a/fast/stages/2-project-factory/schemas/folder.schema.json b/fast/stages/2-project-factory/schemas/folder.schema.json index 393f49d0c..3150efbcd 100644 --- a/fast/stages/2-project-factory/schemas/folder.schema.json +++ b/fast/stages/2-project-factory/schemas/folder.schema.json @@ -4,6 +4,30 @@ "type": "object", "additionalProperties": false, "properties": { + "asset_search": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z0-9-]+$": { + "type": "object", + "additionalProperties": false, + "required": [ + "asset_types" + ], + "properties": { + "asset_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "query": { + "type": "string" + } + } + } + } + }, "asset_feeds": { "type": "object", "additionalProperties": false, @@ -236,6 +260,73 @@ "deletion_protection": { "type": "boolean" }, + "id": { + "type": "string", + "pattern": "^(folders/[0-9]+|\\$folder_ids:[a-z0-9_-]+)$" + }, + "firewall_policy": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "policy" + ], + "properties": { + "name": { + "type": "string" + }, + "policy": { + "type": "string" + } + } + }, + "logging": { + "type": "object", + "additionalProperties": false, + "properties": { + "kms_key_name": { + "type": "string" + }, + "storage_location": { + "type": "string" + }, + "sinks": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9-_]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "exclusions": { + "type": "object" + }, + "filter": { + "type": "string" + }, + "type": { + "type": "string", + "default": "logging", + "enum": [ + "bigquery", + "logging", + "project", + "pubsub", + "storage" + ] + } + } + } + } + } + } + }, "factories_config": { "type": "object", "additionalProperties": false, diff --git a/fast/stages/2-security/schemas/folder.schema.json b/fast/stages/2-security/schemas/folder.schema.json index 393f49d0c..3150efbcd 100644 --- a/fast/stages/2-security/schemas/folder.schema.json +++ b/fast/stages/2-security/schemas/folder.schema.json @@ -4,6 +4,30 @@ "type": "object", "additionalProperties": false, "properties": { + "asset_search": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z0-9-]+$": { + "type": "object", + "additionalProperties": false, + "required": [ + "asset_types" + ], + "properties": { + "asset_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "query": { + "type": "string" + } + } + } + } + }, "asset_feeds": { "type": "object", "additionalProperties": false, @@ -236,6 +260,73 @@ "deletion_protection": { "type": "boolean" }, + "id": { + "type": "string", + "pattern": "^(folders/[0-9]+|\\$folder_ids:[a-z0-9_-]+)$" + }, + "firewall_policy": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "policy" + ], + "properties": { + "name": { + "type": "string" + }, + "policy": { + "type": "string" + } + } + }, + "logging": { + "type": "object", + "additionalProperties": false, + "properties": { + "kms_key_name": { + "type": "string" + }, + "storage_location": { + "type": "string" + }, + "sinks": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9-_]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "exclusions": { + "type": "object" + }, + "filter": { + "type": "string" + }, + "type": { + "type": "string", + "default": "logging", + "enum": [ + "bigquery", + "logging", + "project", + "pubsub", + "storage" + ] + } + } + } + } + } + } + }, "factories_config": { "type": "object", "additionalProperties": false, diff --git a/modules/folder/README.md b/modules/folder/README.md index dc3a39ad0..68998a60a 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -738,29 +738,29 @@ module "folder" { | [assured_workload_config](variables.tf#L61) | Create AssuredWorkloads folder instead of regular folder when value is provided. Incompatible with folder_create=false. | object({…}) | | null | | [autokey_config](variables.tf#L123) | Enable autokey support for this folder's children. Project accepts either project id or number. | object({…}) | | null | | [contacts](variables.tf#L132) | 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)) | | {} | -| [context](variables.tf#L151) | Context-specific interpolations. | object({…}) | | {} | -| [deletion_protection](variables.tf#L171) | Deletion protection setting for this folder. | bool | | false | -| [factories_config](variables.tf#L177) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | -| [firewall_policy](variables.tf#L189) | Hierarchical firewall policy to associate to this folder. | object({…}) | | null | -| [folder_create](variables.tf#L198) | Create folder. When set to false, uses id to reference an existing folder. | bool | | true | +| [context](variables.tf#L151) | Context-specific interpolations. | object({…}) | | {} | +| [deletion_protection](variables.tf#L172) | Deletion protection setting for this folder. | bool | | false | +| [factories_config](variables.tf#L178) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | +| [firewall_policy](variables.tf#L190) | Hierarchical firewall policy to associate to this folder. | object({…}) | | null | +| [folder_create](variables.tf#L201) | Create folder. When set to false, uses id to reference an existing folder. | bool | | true | | [iam](variables-iam.tf#L17) | 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#L61) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | | [iam_by_principals_additive](variables-iam.tf#L54) | Additive IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam_bindings_additive` variable. | map(list(string)) | | {} | | [iam_by_principals_conditional](variables-iam.tf#L68) | Authoritative IAM binding in {PRINCIPAL => {roles = [roles], condition = {cond}}} format. Principals need to be statically defined to avoid errors. Condition is required. | map(object({…})) | | {} | -| [id](variables.tf#L208) | Folder ID in case you use folder_create=false. | string | | null | +| [id](variables.tf#L211) | Folder ID in case you use folder_create=false. | string | | null | | [logging_data_access](variables-logging.tf#L17) | Control activation of data access logs. The special 'allServices' key denotes configuration for all services. | map(object({…})) | | {} | | [logging_exclusions](variables-logging.tf#L28) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_settings](variables-logging.tf#L35) | Default settings for logging resources. | object({…}) | | null | -| [logging_sinks](variables-logging.tf#L45) | Logging sinks to create for the folder. | map(object({…})) | | {} | -| [name](variables.tf#L214) | Folder name. | string | | null | -| [org_policies](variables.tf#L220) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | +| [logging_settings](variables-logging.tf#L35) | Default settings for logging resources. | object({…}) | | null | +| [logging_sinks](variables-logging.tf#L45) | Logging sinks to create for the folder. | map(object({…})) | | {} | +| [name](variables.tf#L217) | Folder name. | string | | null | +| [org_policies](variables.tf#L223) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | | [pam_entitlements](variables-pam.tf#L17) | Privileged Access Manager entitlements for this resource, keyed by entitlement ID. | map(object({…})) | | {} | -| [parent](variables.tf#L248) | Parent in folders/folder_id or organizations/org_id format. | string | | null | +| [parent](variables.tf#L251) | Parent in folders/folder_id or organizations/org_id format. | string | | null | | [scc_mute_configs](variables-scc.tf#L17) | SCC mute configurations keyed by name. | map(object({…})) | | {} | | [scc_sha_custom_modules](variables-scc.tf#L27) | SCC custom modules keyed by module name. | map(object({…})) | | {} | -| [tag_bindings](variables.tf#L262) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | +| [tag_bindings](variables.tf#L265) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | ## Outputs diff --git a/modules/folder/logging.tf b/modules/folder/logging.tf index a44f62b26..ca0e12479 100644 --- a/modules/folder/logging.tf +++ b/modules/folder/logging.tf @@ -60,7 +60,12 @@ resource "google_logging_folder_settings" "default" { count = var.logging_settings != null ? 1 : 0 folder = local.folder_id disable_default_sink = var.logging_settings.disable_default_sink - storage_location = var.logging_settings.storage_location + kms_key_name = ( + var.logging_settings.kms_key_name == null + ? null + : lookup(local.ctx.kms_keys, var.logging_settings.kms_key_name, var.logging_settings.kms_key_name) + ) + storage_location = var.logging_settings.storage_location } resource "google_folder_iam_audit_config" "default" { diff --git a/modules/folder/main.tf b/modules/folder/main.tf index ca6ac2e99..2dc96584c 100644 --- a/modules/folder/main.tf +++ b/modules/folder/main.tf @@ -21,12 +21,17 @@ locals { } if k != "condition_vars" } ctx_p = "$" + _folder_id = ( + var.id == null + ? null + : lookup(local.ctx.folder_ids, var.id, var.id) + ) folder_id = ( var.assured_workload_config == null ? ( var.folder_create - ? try(google_folder.folder[0].id, null) - : var.id + ? coalesce(local._folder_id, try(google_folder.folder[0].id, "")) + : local._folder_id ) : format("folders/%s", try(google_assured_workloads_workload.folder[0].resources[0].resource_id, "")) ) diff --git a/modules/folder/variables-logging.tf b/modules/folder/variables-logging.tf index ee137dd7c..df1db5f95 100644 --- a/modules/folder/variables-logging.tf +++ b/modules/folder/variables-logging.tf @@ -35,8 +35,8 @@ variable "logging_exclusions" { variable "logging_settings" { description = "Default settings for logging resources." type = object({ - # TODO: add support for CMEK disable_default_sink = optional(bool) + kms_key_name = optional(string) storage_location = optional(string) }) default = null @@ -45,16 +45,16 @@ variable "logging_settings" { variable "logging_sinks" { description = "Logging sinks to create for the folder." type = map(object({ + destination = string + type = string bq_partitioned_table = optional(bool, false) description = optional(string) - destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = optional(string) iam = optional(bool, true) include_children = optional(bool, true) intercept_children = optional(bool, false) - type = string })) default = {} nullable = false diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf index d7f3f75f4..f90ef2eaa 100644 --- a/modules/folder/variables.tf +++ b/modules/folder/variables.tf @@ -157,6 +157,7 @@ variable "context" { email_addresses = optional(map(string), {}) folder_ids = optional(map(string), {}) iam_principals = optional(map(string), {}) + kms_keys = optional(map(string), {}) log_buckets = optional(map(string), {}) project_ids = optional(map(string), {}) project_numbers = optional(map(string), {}) @@ -195,6 +196,8 @@ variable "firewall_policy" { default = null } +# keep the following variable as it allows passing in a dynamic value for id + variable "folder_create" { description = "Create folder. When set to false, uses id to reference an existing folder." type = bool diff --git a/modules/organization/README.md b/modules/organization/README.md index c54248f32..a9ad45a78 100644 --- a/modules/organization/README.md +++ b/modules/organization/README.md @@ -997,14 +997,14 @@ module "org" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [organization_id](variables.tf#L172) | Organization id in organizations/nnnnnn format. | string | ✓ | | +| [organization_id](variables.tf#L173) | Organization id in organizations/nnnnnn format. | string | ✓ | | | [asset_feeds](variables.tf#L18) | Cloud Asset Inventory feeds. | map(object({…})) | | {} | | [asset_search](variables.tf#L51) | Cloud Asset Inventory search configurations. | map(object({…})) | | {} | | [contacts](variables.tf#L61) | 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)) | | {} | -| [context](variables.tf#L79) | Context-specific interpolations. | object({…}) | | {} | -| [custom_roles](variables.tf#L99) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | -| [factories_config](variables.tf#L106) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | -| [firewall_policy](variables.tf#L121) | Hierarchical firewall policies to associate to the organization. | object({…}) | | null | +| [context](variables.tf#L79) | Context-specific interpolations. | object({…}) | | {} | +| [custom_roles](variables.tf#L100) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | +| [factories_config](variables.tf#L107) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | +| [firewall_policy](variables.tf#L122) | Hierarchical firewall policies to associate to the organization. | object({…}) | | null | | [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({…})) | | {} | @@ -1014,10 +1014,10 @@ module "org" { | [logging_data_access](variables-logging.tf#L17) | Control activation of data access logs. The special 'allServices' key denotes configuration for all services. | map(object({…})) | | {} | | [logging_exclusions](variables-logging.tf#L28) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string) | | {} | | [logging_settings](variables-logging.tf#L35) | Default settings for logging resources. | object({…}) | | null | -| [logging_sinks](variables-logging.tf#L46) | Logging sinks to create for the organization. | map(object({…})) | | {} | +| [logging_sinks](variables-logging.tf#L45) | Logging sinks to create for the organization. | map(object({…})) | | {} | | [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#L130) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | -| [org_policy_custom_constraints](variables.tf#L158) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} | +| [org_policies](variables.tf#L131) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | +| [org_policy_custom_constraints](variables.tf#L159) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} | | [pam_entitlements](variables-pam.tf#L17) | Privileged Access Manager entitlements for this resource, keyed by entitlement ID. | map(object({…})) | | {} | | [scc_mute_configs](variables-scc.tf#L17) | SCC mute configurations keyed by name. | map(object({…})) | | {} | | [scc_sha_custom_modules](variables-scc.tf#L28) | SCC custom modules keyed by module name. | map(object({…})) | | {} | diff --git a/modules/organization/logging.tf b/modules/organization/logging.tf index bf3d920df..f88b61f02 100644 --- a/modules/organization/logging.tf +++ b/modules/organization/logging.tf @@ -60,7 +60,11 @@ resource "google_logging_organization_settings" "default" { count = var.logging_settings != null ? 1 : 0 organization = local.organization_id_numeric disable_default_sink = var.logging_settings.disable_default_sink - kms_key_name = var.logging_settings.kms_key_name + kms_key_name = ( + var.logging_settings.kms_key_name == null + ? null + : lookup(local.ctx.kms_keys, var.logging_settings.kms_key_name, var.logging_settings.kms_key_name) + ) storage_location = lookup( local.ctx.locations, coalesce(var.logging_settings.storage_location, ""), diff --git a/modules/organization/variables-logging.tf b/modules/organization/variables-logging.tf index 6b56295f9..3ef52cc2f 100644 --- a/modules/organization/variables-logging.tf +++ b/modules/organization/variables-logging.tf @@ -35,7 +35,6 @@ variable "logging_exclusions" { variable "logging_settings" { description = "Default settings for logging resources." type = object({ - # TODO: add support for CMEK disable_default_sink = optional(bool) kms_key_name = optional(string) storage_location = optional(string) diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf index 03ce35388..478dc4469 100644 --- a/modules/organization/variables.tf +++ b/modules/organization/variables.tf @@ -84,6 +84,7 @@ variable "context" { custom_roles = optional(map(string), {}) email_addresses = optional(map(string), {}) iam_principals = optional(map(string), {}) + kms_keys = optional(map(string), {}) locations = optional(map(string), {}) log_buckets = optional(map(string), {}) project_ids = optional(map(string), {}) diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md index 47a9b7abd..10b5bbcf9 100644 --- a/modules/project-factory/README.md +++ b/modules/project-factory/README.md @@ -878,7 +878,7 @@ compute.disableSerialPortAccess: | [data_defaults](variables.tf#L42) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} | | [data_merges](variables.tf#L107) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} | | [data_overrides](variables.tf#L126) | 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({…})) | | {} | +| [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({…})) | | {} | diff --git a/modules/project-factory/folders.tf b/modules/project-factory/folders.tf index ba69797c5..8338d7c7c 100644 --- a/modules/project-factory/folders.tf +++ b/modules/project-factory/folders.tf @@ -54,6 +54,8 @@ module "folder-1" { for_each = { for k, v in local.folders_input : k => v if v.level == 1 } + folder_create = lookup(each.value, "id", null) == null + id = lookup(each.value, "id", null) deletion_protection = lookup(each.value, "deletion_protection", false) parent = coalesce(each.value.parent, "$folder_ids:default") name = each.value.name @@ -65,6 +67,7 @@ module "folder-1" { pam_entitlements = lookup(each.value, "pam_entitlements", {}) tag_bindings = lookup(each.value, "tag_bindings", {}) assured_workload_config = lookup(each.value, "assured_workload_config", null) + logging_settings = lookup(each.value, "logging", null) context = local.ctx } @@ -73,13 +76,14 @@ module "folder-1-iam" { for_each = { for k, v in local.folders_input : k => v if v.level == 1 } - id = module.folder-1[each.key].id - asset_feeds = lookup(each.value, "asset_feeds", {}) + folder_create = false + id = module.folder-1[each.key].id + asset_feeds = lookup(each.value, "asset_feeds", {}) + asset_search = lookup(each.value, "asset_search", {}) factories_config = { # we do anything that can refer to IAM and custom roles in this call pam_entitlements = try(each.value.factories_config.pam_entitlements, null) } - folder_create = false autokey_config = lookup(each.value, "autokey_config", null) iam = lookup(each.value, "iam", {}) iam_bindings = lookup(each.value, "iam_bindings", {}) @@ -88,8 +92,10 @@ module "folder-1-iam" { iam_by_principals_additive = lookup(each.value, "iam_by_principals_additive", {}) iam_by_principals_conditional = lookup(each.value, "iam_by_principals_conditional", {}) logging_data_access = lookup(each.value, "data_access_logs", {}) + logging_sinks = try(each.value.logging.sinks, {}) context = merge(local.ctx, { iam_principals = local.ctx_iam_principals + kms_keys = merge(local.ctx.kms_keys, local.kms_keys) project_ids = local.ctx_project_ids project_numbers = local.ctx_project_numbers }) @@ -100,6 +106,8 @@ module "folder-2" { for_each = { for k, v in local.folders_input : k => v if v.level == 2 } + folder_create = lookup(each.value, "id", null) == null + id = lookup(each.value, "id", null) deletion_protection = lookup(each.value, "deletion_protection", false) parent = coalesce( each.value.parent, "$folder_ids:${each.value.parent_key}" @@ -113,6 +121,7 @@ module "folder-2" { pam_entitlements = lookup(each.value, "pam_entitlements", {}) tag_bindings = lookup(each.value, "tag_bindings", {}) assured_workload_config = lookup(each.value, "assured_workload_config", null) + logging_settings = lookup(each.value, "logging", null) context = merge(local.ctx, { folder_ids = merge(local.ctx.folder_ids, { for k, v in module.folder-1 : k => v.id @@ -126,13 +135,14 @@ module "folder-2-iam" { for_each = { for k, v in local.folders_input : k => v if v.level == 2 } - asset_feeds = lookup(each.value, "asset_feeds", {}) - id = module.folder-2[each.key].id + folder_create = false + id = module.folder-2[each.key].id + asset_feeds = lookup(each.value, "asset_feeds", {}) + asset_search = lookup(each.value, "asset_search", {}) factories_config = { # we do anything that can refer to IAM and custom roles in this call pam_entitlements = try(each.value.factories_config.pam_entitlements, null) } - folder_create = false autokey_config = lookup(each.value, "autokey_config", null) iam = lookup(each.value, "iam", {}) iam_bindings = lookup(each.value, "iam_bindings", {}) @@ -141,11 +151,13 @@ module "folder-2-iam" { iam_by_principals_additive = lookup(each.value, "iam_by_principals_additive", {}) iam_by_principals_conditional = lookup(each.value, "iam_by_principals_conditional", {}) logging_data_access = lookup(each.value, "data_access_logs", {}) + logging_sinks = try(each.value.logging.sinks, {}) context = merge(local.ctx, { folder_ids = merge(local.ctx.folder_ids, { for k, v in module.folder-1 : k => v.id }) iam_principals = local.ctx_iam_principals + kms_keys = merge(local.ctx.kms_keys, local.kms_keys) project_ids = local.ctx_project_ids project_numbers = local.ctx_project_numbers }) @@ -156,6 +168,8 @@ module "folder-3" { for_each = { for k, v in local.folders_input : k => v if v.level == 3 } + folder_create = lookup(each.value, "id", null) == null + id = lookup(each.value, "id", null) deletion_protection = lookup(each.value, "deletion_protection", false) parent = coalesce( each.value.parent, "$folder_ids:${each.value.parent_key}" @@ -169,6 +183,7 @@ module "folder-3" { pam_entitlements = lookup(each.value, "pam_entitlements", {}) tag_bindings = lookup(each.value, "tag_bindings", {}) assured_workload_config = lookup(each.value, "assured_workload_config", null) + logging_settings = lookup(each.value, "logging", null) context = merge(local.ctx, { folder_ids = merge(local.ctx.folder_ids, { for k, v in module.folder-2 : k => v.id @@ -182,13 +197,14 @@ module "folder-3-iam" { for_each = { for k, v in local.folders_input : k => v if v.level == 3 } - id = module.folder-3[each.key].id - asset_feeds = lookup(each.value, "asset_feeds", {}) + folder_create = false + id = module.folder-3[each.key].id + asset_feeds = lookup(each.value, "asset_feeds", {}) + asset_search = lookup(each.value, "asset_search", {}) factories_config = { # we do anything that can refer to IAM and custom roles in this call pam_entitlements = try(each.value.factories_config.pam_entitlements, null) } - folder_create = false autokey_config = lookup(each.value, "autokey_config", null) iam = lookup(each.value, "iam", {}) iam_bindings = lookup(each.value, "iam_bindings", {}) @@ -197,11 +213,13 @@ module "folder-3-iam" { iam_by_principals_additive = lookup(each.value, "iam_by_principals_additive", {}) iam_by_principals_conditional = lookup(each.value, "iam_by_principals_conditional", {}) logging_data_access = lookup(each.value, "data_access_logs", {}) + logging_sinks = try(each.value.logging.sinks, {}) context = merge(local.ctx, { folder_ids = merge(local.ctx.folder_ids, { for k, v in module.folder-2 : k => v.id }) iam_principals = local.ctx_iam_principals + kms_keys = merge(local.ctx.kms_keys, local.kms_keys) project_ids = local.ctx_project_ids project_numbers = local.ctx_project_numbers }) @@ -212,6 +230,8 @@ module "folder-4" { for_each = { for k, v in local.folders_input : k => v if v.level == 4 } + folder_create = lookup(each.value, "id", null) == null + id = lookup(each.value, "id", null) deletion_protection = lookup(each.value, "deletion_protection", false) parent = coalesce( each.value.parent, "$folder_ids:${each.value.parent_key}" @@ -225,6 +245,7 @@ module "folder-4" { pam_entitlements = lookup(each.value, "pam_entitlements", {}) tag_bindings = lookup(each.value, "tag_bindings", {}) assured_workload_config = lookup(each.value, "assured_workload_config", null) + logging_settings = lookup(each.value, "logging", null) context = merge(local.ctx, { folder_ids = merge(local.ctx.folder_ids, { for k, v in module.folder-3 : k => v.id @@ -238,13 +259,14 @@ module "folder-4-iam" { for_each = { for k, v in local.folders_input : k => v if v.level == 4 } - id = module.folder-4[each.key].id - asset_feeds = lookup(each.value, "asset_feeds", {}) + folder_create = false + id = module.folder-4[each.key].id + asset_feeds = lookup(each.value, "asset_feeds", {}) + asset_search = lookup(each.value, "asset_search", {}) factories_config = { # we do anything that can refer to IAM and custom roles in this call pam_entitlements = try(each.value.factories_config.pam_entitlements, null) } - folder_create = false autokey_config = lookup(each.value, "autokey_config", null) iam = lookup(each.value, "iam", {}) iam_bindings = lookup(each.value, "iam_bindings", {}) @@ -253,11 +275,13 @@ module "folder-4-iam" { iam_by_principals_additive = lookup(each.value, "iam_by_principals_additive", {}) iam_by_principals_conditional = lookup(each.value, "iam_by_principals_conditional", {}) logging_data_access = lookup(each.value, "data_access_logs", {}) + logging_sinks = try(each.value.logging.sinks, {}) context = merge(local.ctx, { folder_ids = merge(local.ctx.folder_ids, { for k, v in module.folder-3 : k => v.id }) iam_principals = local.ctx_iam_principals + kms_keys = merge(local.ctx.kms_keys, local.kms_keys) project_ids = local.ctx_project_ids project_numbers = local.ctx_project_numbers }) diff --git a/modules/project-factory/schemas/folder.schema.json b/modules/project-factory/schemas/folder.schema.json index 393f49d0c..3150efbcd 100644 --- a/modules/project-factory/schemas/folder.schema.json +++ b/modules/project-factory/schemas/folder.schema.json @@ -4,6 +4,30 @@ "type": "object", "additionalProperties": false, "properties": { + "asset_search": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z0-9-]+$": { + "type": "object", + "additionalProperties": false, + "required": [ + "asset_types" + ], + "properties": { + "asset_types": { + "type": "array", + "items": { + "type": "string" + } + }, + "query": { + "type": "string" + } + } + } + } + }, "asset_feeds": { "type": "object", "additionalProperties": false, @@ -236,6 +260,73 @@ "deletion_protection": { "type": "boolean" }, + "id": { + "type": "string", + "pattern": "^(folders/[0-9]+|\\$folder_ids:[a-z0-9_-]+)$" + }, + "firewall_policy": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "policy" + ], + "properties": { + "name": { + "type": "string" + }, + "policy": { + "type": "string" + } + } + }, + "logging": { + "type": "object", + "additionalProperties": false, + "properties": { + "kms_key_name": { + "type": "string" + }, + "storage_location": { + "type": "string" + }, + "sinks": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z][a-z0-9-_]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "destination": { + "type": "string" + }, + "exclusions": { + "type": "object" + }, + "filter": { + "type": "string" + }, + "type": { + "type": "string", + "default": "logging", + "enum": [ + "bigquery", + "logging", + "project", + "pubsub", + "storage" + ] + } + } + } + } + } + } + }, "factories_config": { "type": "object", "additionalProperties": false, diff --git a/modules/project-factory/schemas/folder.schema.md b/modules/project-factory/schemas/folder.schema.md index 846d18c6b..f75f0ccc4 100644 --- a/modules/project-factory/schemas/folder.schema.md +++ b/modules/project-factory/schemas/folder.schema.md @@ -6,6 +6,13 @@ *additional properties: false* +- **asset_search**: *object* +
*additional properties: false* + - **`^[a-z0-9-]+$`**: *object* +
*additional properties: false* + - ⁺**asset_types**: *array* + - items: *string* + - **query**: *string* - **asset_feeds**: *object*
*additional properties: false* - **`^[a-z0-9-]+$`**: *object* @@ -75,6 +82,24 @@ - **exempted_members**: *array* - items: *string* - **deletion_protection**: *boolean* +- **firewall_policy**: *object* +
*additional properties: false* + - ⁺**name**: *string* + - ⁺**policy**: *string* +- **logging**: *object* +
*additional properties: false* + - **kms_key_name**: *string* + - **storage_location**: *string* + - **sinks**: *object* +
*additional properties: false* + - **`^[a-z][a-z0-9-_]+$`**: *object* +
*additional properties: false* + - **description**: *string* + - **destination**: *string* + - **exclusions**: *object* + - **filter**: *string* + - **type**: *string* +
*default: logging*, *enum: ['bigquery', 'logging', 'project', 'pubsub', 'storage']* - **factories_config**: *object*
*additional properties: false* - **org_policies**: *string* diff --git a/modules/project-factory/variables-folders.tf b/modules/project-factory/variables-folders.tf index d98fc70da..f8b4298cc 100644 --- a/modules/project-factory/variables-folders.tf +++ b/modules/project-factory/variables-folders.tf @@ -17,6 +17,10 @@ variable "folders" { description = "Folders data merged with factory data." type = map(object({ + asset_search = optional(map(object({ + asset_types = list(string) + query = optional(string) + })), {}) asset_feeds = optional(map(object({ billing_project = string content_type = optional(string) @@ -49,10 +53,31 @@ variable "folders" { })) violation_notifications_enabled = optional(bool) }), null) + contacts = optional(map(list(string)), {}) + id = optional(string) name = optional(string) parent = optional(string) deletion_protection = optional(bool) - iam = optional(map(list(string)), {}) + firewall_policy = optional(object({ + name = string + policy = string + })) + logging = optional(object({ + kms_key_name = optional(string) + storage_location = optional(string) + sinks = optional(map(object({ + description = optional(string) + destination = string + disabled = optional(bool, false) + exclusions = optional(map(string), {}) + filter = optional(string) + iam = optional(bool, true) + include_children = optional(bool, true) + intercept_children = optional(bool, false) + type = optional(string, "logging") + })), {}) + })) + iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) role = string diff --git a/tests/modules/folder/context.tfvars b/tests/modules/folder/context.tfvars index edb15a6b0..3ff9670bc 100644 --- a/tests/modules/folder/context.tfvars +++ b/tests/modules/folder/context.tfvars @@ -16,6 +16,9 @@ context = { folder_ids = { default = "organizations/1234567890" } + kms_keys = { + test = "projects/test-kms-0/locations/europe-west8/keyRings/test/cryptoKeys/test" + } iam_principals = { mygroup = "group:test-group@example.com" mysa = "serviceAccount:test@test-project.iam.gserviceaccount.com" @@ -95,6 +98,9 @@ logging_data_access = { DATA_READ = {} } } +logging_settings = { + kms_key_name = "$kms_keys:test" +} logging_sinks = { test-pubsub = { destination = "$pubsub_topics:test" diff --git a/tests/modules/folder/context.yaml b/tests/modules/folder/context.yaml index 08aec8d75..af68b8651 100644 --- a/tests/modules/folder/context.yaml +++ b/tests/modules/folder/context.yaml @@ -96,6 +96,9 @@ values: condition: [] member: user:test-user@example.com role: organizations/366118655033/roles/myRoleTwo + google_logging_folder_settings.default[0]: + kms_key_name: projects/test-kms-0/locations/europe-west8/keyRings/test/cryptoKeys/test + timeouts: null google_logging_folder_sink.sink["test-pubsub"]: description: test-pubsub (Terraform-managed). destination: pubsub.googleapis.com/projects/test-prod-audit-logs-0/topics/audit-logs @@ -153,9 +156,10 @@ counts: google_folder_iam_audit_config: 1 google_folder_iam_binding: 7 google_folder_iam_member: 1 + google_logging_folder_settings: 1 google_logging_folder_sink: 1 google_privileged_access_manager_entitlement: 1 google_pubsub_topic_iam_member: 1 google_tags_tag_binding: 1 modules: 0 - resources: 16 + resources: 17 diff --git a/tests/modules/folder/main.tf b/tests/modules/folder/main.tf deleted file mode 100644 index 46724107f..000000000 --- a/tests/modules/folder/main.tf +++ /dev/null @@ -1,104 +0,0 @@ -/** - * 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. - */ - -locals { - ctx = { - custom_roles = { - # mixing in locally managed roles triggers a cycle - for k, v in var.factories_config.context.custom_roles : - "${local.ctx_p}custom_roles:${k}" => v - } - iam_principals = { - for k, v in var.factories_config.context.iam_principals : - "${local.ctx_p}iam_principals:${k}" => v - } - } - ctx_p = "$" - folder_id = ( - var.assured_workload_config == null - ? ( - var.folder_create - ? try(google_folder.folder[0].id, null) - : var.id - ) - : format("folders/%s", try(google_assured_workloads_workload.folder[0].resources[0].resource_id, "")) - ) - aw_parent = ( - # Assured Workload only accepls folder as a parent and uses organization as a parent when no value provided. - var.parent == null - ? null - : ( - try(startswith(var.parent, "folders/")) - ? var.parent - : null - ) - ) -} - -resource "google_folder" "folder" { - count = var.folder_create && var.assured_workload_config == null ? 1 : 0 - display_name = var.name - parent = var.parent - deletion_protection = var.deletion_protection -} - -resource "google_essential_contacts_contact" "contact" { - provider = google-beta - for_each = var.contacts - parent = local.folder_id - email = each.key - language_tag = "en" - notification_category_subscriptions = each.value - depends_on = [ - google_folder_iam_binding.authoritative, - google_folder_iam_binding.bindings, - google_folder_iam_member.bindings - ] -} - -resource "google_compute_firewall_policy_association" "default" { - count = var.firewall_policy == null ? 0 : 1 - attachment_target = local.folder_id - name = var.firewall_policy.name - firewall_policy = var.firewall_policy.policy -} - -resource "google_assured_workloads_workload" "folder" { - count = (var.assured_workload_config != null && var.folder_create) ? 1 : 0 - compliance_regime = var.assured_workload_config.compliance_regime - display_name = var.assured_workload_config.display_name - location = var.assured_workload_config.location - organization = var.assured_workload_config.organization - enable_sovereign_controls = var.assured_workload_config.enable_sovereign_controls - labels = var.assured_workload_config.labels - partner = var.assured_workload_config.partner - dynamic "partner_permissions" { - for_each = try(var.assured_workload_config.partner_permissions, null) == null ? [] : [""] - content { - assured_workloads_monitoring = var.assured_workload_config.partner_permissions.assured_workloads_monitoring - data_logs_viewer = var.assured_workload_config.partner_permissions.data_logs_viewer - service_access_approver = var.assured_workload_config.partner_permissions.service_access_approver - } - } - - provisioned_resources_parent = local.aw_parent - - resource_settings { - display_name = var.name - resource_type = "CONSUMER_FOLDER" - } - violation_notifications_enabled = var.assured_workload_config.violation_notifications_enabled -} diff --git a/tests/modules/organization/context.tfvars b/tests/modules/organization/context.tfvars index 50af9f7da..0f6ec772a 100644 --- a/tests/modules/organization/context.tfvars +++ b/tests/modules/organization/context.tfvars @@ -2,6 +2,9 @@ context = { bigquery_datasets = { test = "projects/test-prod-audit-logs-0/datasets/logs" } + kms_keys = { + test = "projects/test-kms-0/locations/europe-west8/keyRings/test/cryptoKeys/test" + } condition_vars = { organization = { id = 1234567890 @@ -137,6 +140,7 @@ logging_sinks = { } } logging_settings = { + kms_key_name = "$kms_keys:test" storage_location = "$locations:default" } pam_entitlements = { diff --git a/tests/modules/organization/context.yaml b/tests/modules/organization/context.yaml index 4799f95fe..16096a61e 100644 --- a/tests/modules/organization/context.yaml +++ b/tests/modules/organization/context.yaml @@ -38,6 +38,7 @@ values: parent: organizations/1234567890 timeouts: null google_logging_organization_settings.default[0]: + kms_key_name: projects/test-kms-0/locations/europe-west8/keyRings/test/cryptoKeys/test organization: '1234567890' storage_location: europe-west8 timeouts: null From f794d764e9b68f4946ad9a0a41a90ec4d38ac0c8 Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Wed, 4 Mar 2026 11:06:48 +0100 Subject: [PATCH 3/3] Support additional dns_access attributes in GKE cluster modules (#3781) --- fast/stages/3-gke-dev/README.md | 14 ++--- fast/stages/3-gke-dev/variables.tf | 6 +- modules/gke-cluster-autopilot/README.md | 43 ++++++------- modules/gke-cluster-autopilot/main.tf | 4 +- modules/gke-cluster-autopilot/variables.tf | 6 +- modules/gke-cluster-standard/README.md | 64 +++++++++++--------- modules/gke-cluster-standard/main.tf | 4 +- modules/gke-cluster-standard/variables.tf | 6 +- tests/fast/stages/s3_gke_dev/hardened.tfvars | 1 - 9 files changed, 82 insertions(+), 66 deletions(-) diff --git a/fast/stages/3-gke-dev/README.md b/fast/stages/3-gke-dev/README.md index 48a8331f0..7e7b34764 100644 --- a/fast/stages/3-gke-dev/README.md +++ b/fast/stages/3-gke-dev/README.md @@ -185,18 +185,18 @@ Clusters can then be configured for fleet registration and one of the config man | [billing_account](variables-fast.tf#L26) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…}) | ✓ | | 0-org-setup | | [environments](variables-fast.tf#L34) | Long environment names. | object({…}) | ✓ | | 0-org-setup | | [prefix](variables-fast.tf#L60) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-org-setup | -| [clusters](variables.tf#L17) | Clusters configuration. Refer to the gke-cluster module for type details. | map(object({…})) | | {} | | -| [deletion_protection](variables.tf#L102) | Prevent Terraform from destroying data resources. | bool | | false | | +| [clusters](variables.tf#L17) | Clusters configuration. Refer to the gke-cluster module for type details. | map(object({…})) | | {} | | +| [deletion_protection](variables.tf#L106) | Prevent Terraform from destroying data resources. | bool | | false | | | [fleet_config](variables-fleet.tf#L19) | Fleet configuration. | object({…}) | | null | | | [fleet_configmanagement_templates](variables-fleet.tf#L35) | Sets of fleet configurations that can be applied to member clusters, in config name => {options} format. | map(object({…})) | | {} | | | [folder_ids](variables-fast.tf#L44) | Folder name => id mappings. | map(string) | | {} | 0-org-setup | | [host_project_ids](variables-fast.tf#L52) | Shared VPC host project name => id mappings. | map(string) | | {} | 2-networking | -| [iam](variables.tf#L109) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | -| [iam_by_principals](variables.tf#L116) | 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)) | | {} | | -| [nodepools](variables.tf#L123) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | | -| [stage_config](variables.tf#L172) | FAST stage configuration used to find resource ids. Must match name defined for the stage in resource management. | object({…}) | | {…} | | +| [iam](variables.tf#L113) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | +| [iam_by_principals](variables.tf#L120) | 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)) | | {} | | +| [nodepools](variables.tf#L127) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | | +| [stage_config](variables.tf#L176) | FAST stage configuration used to find resource ids. Must match name defined for the stage in resource management. | object({…}) | | {…} | | | [subnet_self_links](variables-fast.tf#L70) | Subnet VPC name => { name => self link } mappings. | map(map(string)) | | {} | 2-networking | -| [vpc_config](variables.tf#L184) | VPC-level configuration for project and clusters. | object({…}) | | {…} | | +| [vpc_config](variables.tf#L188) | VPC-level configuration for project and clusters. | object({…}) | | {…} | | | [vpc_self_links](variables-fast.tf#L78) | Shared VPC name => self link mappings. | map(string) | | {} | 2-networking | ## Outputs diff --git a/fast/stages/3-gke-dev/variables.tf b/fast/stages/3-gke-dev/variables.tf index 31bfc62fc..2a34eaea7 100644 --- a/fast/stages/3-gke-dev/variables.tf +++ b/fast/stages/3-gke-dev/variables.tf @@ -18,7 +18,11 @@ variable "clusters" { description = "Clusters configuration. Refer to the gke-cluster module for type details." type = map(object({ access_config = optional(object({ - dns_access = optional(bool, true) + dns_access = optional(object({ + allow_external_traffic = optional(bool, true) + enable_k8s_tokens = optional(bool) + enable_k8s_certs = optional(bool) + }), {}) ip_access = optional(object({ authorized_ranges = optional(map(string), {}) disable_public_endpoint = optional(bool, true) diff --git a/modules/gke-cluster-autopilot/README.md b/modules/gke-cluster-autopilot/README.md index 5b5ad6262..16558d33b 100644 --- a/modules/gke-cluster-autopilot/README.md +++ b/modules/gke-cluster-autopilot/README.md @@ -247,9 +247,6 @@ module "cluster-1" { project_id = "myproject" name = "cluster-1" location = "europe-west1" - access_config = { - dns_access = true - } vpc_config = { network = var.vpc.self_link subnetwork = var.subnet.self_link @@ -294,26 +291,26 @@ module "cluster-1" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [location](variables.tf#L180) | Autopilot clusters are always regional. | string | ✓ | | -| [name](variables.tf#L259) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L292) | Cluster project ID. | string | ✓ | | -| [vpc_config](variables.tf#L308) | 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#L162) | The name of the fleet host project where this cluster will be registered. | string | | null | -| [issue_client_certificate](variables.tf#L168) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L174) | Cluster resource labels. | map(string) | | null | -| [logging_config](variables.tf#L185) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L196) | Maintenance window configuration. | object({…}) | | {…} | -| [min_master_version](variables.tf#L219) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L225) | 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#L264) | Configuration for nodes and nodepools. | object({…}) | | {} | -| [node_locations](variables.tf#L285) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [release_channel](variables.tf#L297) | Release channel for GKE upgrades. Clusters created in the Autopilot mode must use a release channel. Choose between \"RAPID\", \"REGULAR\", and \"STABLE\". | string | | "REGULAR" | +| [location](variables.tf#L184) | Autopilot clusters are always regional. | string | ✓ | | +| [name](variables.tf#L263) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L296) | Cluster project ID. | string | ✓ | | +| [vpc_config](variables.tf#L312) | VPC-level configuration. | object({…}) | ✓ | | +| [access_config](variables.tf#L17) | Control plane endpoint and nodes access configurations. | object({…}) | | {} | +| [backup_configs](variables.tf#L49) | Configuration for Backup for GKE. | object({…}) | | {} | +| [deletion_protection](variables.tf#L71) | 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#L78) | Cluster description. | string | | null | +| [enable_addons](variables.tf#L84) | Addons enabled in the cluster (true means enabled). | object({…}) | | {} | +| [enable_features](variables.tf#L98) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | +| [fleet_project](variables.tf#L166) | The name of the fleet host project where this cluster will be registered. | string | | null | +| [issue_client_certificate](variables.tf#L172) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L178) | Cluster resource labels. | map(string) | | null | +| [logging_config](variables.tf#L189) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L200) | Maintenance window configuration. | object({…}) | | {…} | +| [min_master_version](variables.tf#L223) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L229) | 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#L268) | Configuration for nodes and nodepools. | object({…}) | | {} | +| [node_locations](variables.tf#L289) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [release_channel](variables.tf#L301) | 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 1ec7ee9ae..2879478fb 100644 --- a/modules/gke-cluster-autopilot/main.tf +++ b/modules/gke-cluster-autopilot/main.tf @@ -84,7 +84,9 @@ resource "google_container_cluster" "cluster" { } control_plane_endpoints_config { dns_endpoint_config { - allow_external_traffic = var.access_config.dns_access == true + allow_external_traffic = var.access_config.dns_access.allow_external_traffic == true + enable_k8s_tokens_via_dns = var.access_config.dns_access.enable_k8s_tokens + enable_k8s_certs_via_dns = var.access_config.dns_access.enable_k8s_certs } ip_endpoints_config { enabled = var.access_config.ip_access != null diff --git a/modules/gke-cluster-autopilot/variables.tf b/modules/gke-cluster-autopilot/variables.tf index 44ac36f35..d4dfaa0bc 100644 --- a/modules/gke-cluster-autopilot/variables.tf +++ b/modules/gke-cluster-autopilot/variables.tf @@ -17,7 +17,11 @@ variable "access_config" { description = "Control plane endpoint and nodes access configurations." type = object({ - dns_access = optional(bool, true) + dns_access = optional(object({ + allow_external_traffic = optional(bool, true) + enable_k8s_tokens = optional(bool) + enable_k8s_certs = optional(bool) + }), {}) ip_access = optional(object({ authorized_ranges = optional(map(string)) disable_public_endpoint = optional(bool) diff --git a/modules/gke-cluster-standard/README.md b/modules/gke-cluster-standard/README.md index 4596cf3f7..4bffeccd7 100644 --- a/modules/gke-cluster-standard/README.md +++ b/modules/gke-cluster-standard/README.md @@ -43,7 +43,10 @@ module "cluster-1" { location = "europe-west1-b" # access_config can be omitted if master authorized ranges are not needed access_config = { - # dns_access = true + # defaults to true + # dns_access = { + # allow_external_traffic = true + # } ip_access = { authorized_ranges = { internal-vms = "10.0.0.0/8" @@ -78,7 +81,9 @@ module "cluster-1" { name = "cluster-1" location = "europe-west1-b" access_config = { - dns_access = false + dns_access = { + allow_external_traffic = false + } ip_access = { authorized_ranges = { "corporate proxy" = "8.8.8.8/32" @@ -115,7 +120,9 @@ module "cluster-1" { name = "cluster-1" location = "europe-west1-b" access_config = { - dns_access = false + dns_access = { + allow_external_traffic = false + } ip_access = { authorized_ranges = { internal-vms = "10.0.0.0/8" @@ -489,9 +496,6 @@ module "cluster-1" { project_id = "myproject" name = "cluster-1" location = "europe-west1" - access_config = { - dns_access = true - } vpc_config = { network = var.vpc.self_link subnetwork = var.subnet.self_link @@ -511,30 +515,30 @@ module "cluster-1" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [location](variables.tf#L300) | Cluster zone or region. | string | ✓ | | -| [name](variables.tf#L415) | Cluster name. | string | ✓ | | -| [project_id](variables.tf#L467) | Cluster project id. | string | ✓ | | -| [vpc_config](variables.tf#L478) | 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 | -| [default_nodepool](variables.tf#L148) | Enable default nodepool. | object({…}) | | {} | -| [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#L281) | The name of the fleet host project where this cluster will be registered. | string | | null | -| [issue_client_certificate](variables.tf#L287) | Enable issuing client certificate. | bool | | false | -| [labels](variables.tf#L293) | Cluster resource labels. | map(string) | | {} | -| [logging_config](variables.tf#L305) | Logging configuration. | object({…}) | | {} | -| [maintenance_config](variables.tf#L326) | Maintenance window configuration. | object({…}) | | {…} | -| [max_pods_per_node](variables.tf#L349) | Maximum number of pods per node in this cluster. | number | | 110 | -| [min_master_version](variables.tf#L355) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | -| [monitoring_config](variables.tf#L361) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | -| [node_config](variables.tf#L420) | Node-level configuration. | object({…}) | | {} | -| [node_locations](variables.tf#L443) | Zones in which the cluster's nodes are located. | list(string) | | [] | -| [node_pool_auto_config](variables.tf#L450) | Node pool configs that apply to auto-provisioned node pools in autopilot clusters and node auto-provisioning-enabled clusters. | object({…}) | | {} | -| [release_channel](variables.tf#L472) | Release channel for GKE upgrades. | string | | null | +| [location](variables.tf#L304) | Cluster zone or region. | string | ✓ | | +| [name](variables.tf#L419) | Cluster name. | string | ✓ | | +| [project_id](variables.tf#L471) | Cluster project id. | string | ✓ | | +| [vpc_config](variables.tf#L482) | VPC-level configuration. | object({…}) | ✓ | | +| [access_config](variables.tf#L17) | Control plane endpoint and nodes access configurations. | object({…}) | | {} | +| [backup_configs](variables.tf#L49) | Configuration for Backup for GKE. | object({…}) | | {} | +| [cluster_autoscaling](variables.tf#L72) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | object({…}) | | null | +| [default_nodepool](variables.tf#L152) | Enable default nodepool. | object({…}) | | {} | +| [deletion_protection](variables.tf#L170) | 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#L177) | Cluster description. | string | | null | +| [enable_addons](variables.tf#L183) | Addons enabled in the cluster (true means enabled). | object({…}) | | {} | +| [enable_features](variables.tf#L205) | Enable cluster-level features. Certain features allow configuration. | object({…}) | | {} | +| [fleet_project](variables.tf#L285) | The name of the fleet host project where this cluster will be registered. | string | | null | +| [issue_client_certificate](variables.tf#L291) | Enable issuing client certificate. | bool | | false | +| [labels](variables.tf#L297) | Cluster resource labels. | map(string) | | {} | +| [logging_config](variables.tf#L309) | Logging configuration. | object({…}) | | {} | +| [maintenance_config](variables.tf#L330) | Maintenance window configuration. | object({…}) | | {…} | +| [max_pods_per_node](variables.tf#L353) | Maximum number of pods per node in this cluster. | number | | 110 | +| [min_master_version](variables.tf#L359) | Minimum version of the master, defaults to the version of the most recent official release. | string | | null | +| [monitoring_config](variables.tf#L365) | Monitoring configuration. Google Cloud Managed Service for Prometheus is enabled by default. | object({…}) | | {} | +| [node_config](variables.tf#L424) | Node-level configuration. | object({…}) | | {} | +| [node_locations](variables.tf#L447) | Zones in which the cluster's nodes are located. | list(string) | | [] | +| [node_pool_auto_config](variables.tf#L454) | Node pool configs that apply to auto-provisioned node pools in autopilot clusters and node auto-provisioning-enabled clusters. | object({…}) | | {} | +| [release_channel](variables.tf#L476) | 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 cfd5dc581..36e25821d 100644 --- a/modules/gke-cluster-standard/main.tf +++ b/modules/gke-cluster-standard/main.tf @@ -273,7 +273,9 @@ resource "google_container_cluster" "cluster" { } control_plane_endpoints_config { dns_endpoint_config { - allow_external_traffic = var.access_config.dns_access == true + allow_external_traffic = var.access_config.dns_access.allow_external_traffic == true + enable_k8s_tokens_via_dns = var.access_config.dns_access.enable_k8s_tokens + enable_k8s_certs_via_dns = var.access_config.dns_access.enable_k8s_certs } ip_endpoints_config { enabled = var.access_config.ip_access != null diff --git a/modules/gke-cluster-standard/variables.tf b/modules/gke-cluster-standard/variables.tf index 7e6cf4d2d..452dbaa8d 100644 --- a/modules/gke-cluster-standard/variables.tf +++ b/modules/gke-cluster-standard/variables.tf @@ -17,7 +17,11 @@ variable "access_config" { description = "Control plane endpoint and nodes access configurations." type = object({ - dns_access = optional(bool, true) + dns_access = optional(object({ + allow_external_traffic = optional(bool, true) + enable_k8s_tokens = optional(bool) + enable_k8s_certs = optional(bool) + }), {}) ip_access = optional(object({ authorized_ranges = optional(map(string)) disable_public_endpoint = optional(bool) diff --git a/tests/fast/stages/s3_gke_dev/hardened.tfvars b/tests/fast/stages/s3_gke_dev/hardened.tfvars index 13941346f..23d51f2bc 100644 --- a/tests/fast/stages/s3_gke_dev/hardened.tfvars +++ b/tests/fast/stages/s3_gke_dev/hardened.tfvars @@ -16,7 +16,6 @@ clusters = { master_global_access = true } access_config = { - dns_access = true ip_access = { disable_public_endpoint = true }