diff --git a/modules/gke-hub/README.md b/modules/gke-hub/README.md
index 7be0510d0..9d51da585 100644
--- a/modules/gke-hub/README.md
+++ b/modules/gke-hub/README.md
@@ -70,6 +70,7 @@ module "cluster_1" {
module "hub" {
source = "./fabric/modules/gke-hub"
project_id = module.project.project_id
+ location = "europe-west1"
clusters = {
cluster-1 = module.cluster_1.id
}
@@ -291,17 +292,86 @@ module "hub" {
# tftest modules=8 resources=44
```
+
+## Fleet Default Member Configuration Example
+
+This example demonstrates how to use the enhanced `fleet_default_member_config` to configure default settings for all member clusters in the fleet:
+
+```hcl
+module "hub" {
+ source = "./fabric/modules/gke-hub"
+ project_id = module.project.project_id
+ location = "europe-west1"
+ clusters = {
+ cluster-1 = module.cluster_1.id
+ cluster-2 = module.cluster_2.id
+ }
+ features = {
+ configmanagement = true
+ servicemesh = true
+ }
+
+ # Fleet default member configuration
+ fleet_default_member_config = {
+ # Service Mesh configuration
+ mesh = {
+ management = "MANAGEMENT_AUTOMATIC"
+ }
+
+ # Config Management configuration
+ configmanagement = {
+ version = "v1"
+
+ # Config Sync configuration
+ config_sync = {
+ prevent_drift = true
+ source_format = "hierarchy"
+ enabled = true
+ git = {
+ sync_repo = "https://github.com/your-org/config-repo"
+ policy_dir = "configsync"
+ gcp_service_account_email = "config-sync@your-project.iam.gserviceaccount.com"
+ secret_type = "gcenode"
+ sync_branch = "main"
+ sync_rev = "HEAD"
+ sync_wait_secs = 15
+ }
+ }
+ }
+ }
+
+ # Individual cluster configurations (these will override fleet defaults if specified)
+ configmanagement_templates = {
+ cluster-specific = {
+ config_sync = {
+ git = {
+ sync_repo = "https://github.com/your-org/cluster-specific-config"
+ policy_dir = "cluster-specific"
+ sync_branch = "main"
+ }
+ source_format = "hierarchy"
+ }
+ version = "v1"
+ }
+ }
+ configmanagement_clusters = {
+ "cluster-specific" = ["cluster-1"]
+ }
+}
+```
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [project_id](variables.tf#L80) | GKE hub project ID. | string | ✓ | |
+| [project_id](variables.tf#L116) | GKE hub project ID. | string | ✓ | |
| [clusters](variables.tf#L17) | Clusters members of this GKE Hub in name => id format. | map(string) | | {} |
| [configmanagement_clusters](variables.tf#L24) | Config management features enabled on specific sets of member clusters, in config name => [cluster name] format. | map(list(string)) | | {} |
| [configmanagement_templates](variables.tf#L31) | Sets of config management configurations that can be applied to member clusters, in config name => {options} format. | map(object({…})) | | {} |
| [features](variables.tf#L66) | Enable and configure fleet features. | object({…}) | | {} |
-| [workload_identity_clusters](variables.tf#L85) | Clusters that will use Fleet Workload Identity. | list(string) | | [] |
+| [fleet_default_member_config](variables.tf#L80) | Fleet default member config. | object({…}) | | null |
+| [location](variables.tf#L109) | GKE hub location, will also be used for the membership location. | string | | null |
+| [workload_identity_clusters](variables.tf#L121) | Clusters that will use Fleet Workload Identity. | list(string) | | [] |
## Outputs
diff --git a/modules/gke-hub/main.tf b/modules/gke-hub/main.tf
index 740890d6b..57c3fe439 100644
--- a/modules/gke-hub/main.tf
+++ b/modules/gke-hub/main.tf
@@ -38,6 +38,7 @@ resource "google_gke_hub_membership" "default" {
provider = google-beta
for_each = var.clusters
project = var.project_id
+ location = var.location
membership_id = each.key
endpoint {
gke_cluster {
@@ -68,15 +69,57 @@ resource "google_gke_hub_feature" "default" {
}
}
}
+ dynamic "fleet_default_member_config" {
+ for_each = var.fleet_default_member_config != null ? { 1 = 1 } : {}
+ content {
+ dynamic "mesh" {
+ for_each = var.fleet_default_member_config.mesh != null ? { 1 = 1 } : {}
+ content {
+ management = try(mesh.value.management, "MANAGEMENT_AUTOMATIC")
+ }
+ }
+
+ dynamic "configmanagement" {
+ for_each = var.fleet_default_member_config.configmanagement != null ? { 1 = 1 } : {}
+ content {
+ version = configmanagement.value.version
+
+ dynamic "config_sync" {
+ for_each = configmanagement.value.config_sync != null ? { 1 = 1 } : {}
+ content {
+ prevent_drift = config_sync.value.prevent_drift
+ source_format = config_sync.value.source_format
+ enabled = config_sync.value.enabled
+
+ dynamic "git" {
+ for_each = config_sync.value.git != null ? { 1 = 1 } : {}
+ content {
+ gcp_service_account_email = git.value.gcp_service_account_email
+ https_proxy = git.value.https_proxy
+ policy_dir = git.value.policy_dir
+ secret_type = git.value.secret_type
+ sync_branch = git.value.sync_branch
+ sync_repo = git.value.sync_repo
+ sync_rev = git.value.sync_rev
+ sync_wait_secs = git.value.sync_wait_secs
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
resource "google_gke_hub_feature_membership" "servicemesh" {
- provider = google-beta
- for_each = var.features.servicemesh ? var.clusters : {}
- project = var.project_id
- location = "global"
- feature = google_gke_hub_feature.default["servicemesh"].name
- membership = google_gke_hub_membership.default[each.key].membership_id
+ provider = google-beta
+ for_each = var.features.servicemesh ? var.clusters : {}
+ project = var.project_id
+ location = "global"
+ feature = google_gke_hub_feature.default["servicemesh"].name
+ membership = google_gke_hub_membership.default[each.key].membership_id
+ membership_location = var.location
mesh {
management = "MANAGEMENT_AUTOMATIC"
@@ -84,12 +127,13 @@ resource "google_gke_hub_feature_membership" "servicemesh" {
}
resource "google_gke_hub_feature_membership" "default" {
- provider = google-beta
- for_each = local.cluster_cm_config
- project = var.project_id
- location = "global"
- feature = google_gke_hub_feature.default["configmanagement"].name
- membership = google_gke_hub_membership.default[each.key].membership_id
+ provider = google-beta
+ for_each = local.cluster_cm_config
+ project = var.project_id
+ location = "global"
+ feature = google_gke_hub_feature.default["configmanagement"].name
+ membership = google_gke_hub_membership.default[each.key].membership_id
+ membership_location = var.location
configmanagement {
version = each.value.version
diff --git a/modules/gke-hub/variables.tf b/modules/gke-hub/variables.tf
index 8f31d32b6..8149c8466 100644
--- a/modules/gke-hub/variables.tf
+++ b/modules/gke-hub/variables.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 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.
@@ -77,6 +77,42 @@ variable "features" {
nullable = false
}
+variable "fleet_default_member_config" {
+ description = "Fleet default member config."
+ type = object({
+ mesh = optional(object({
+ management = optional(string, "MANAGEMENT_AUTOMATIC")
+ }))
+ configmanagement = optional(object({
+ version = optional(string)
+ config_sync = optional(object({
+ prevent_drift = optional(bool)
+ source_format = optional(string, "hierarchy")
+ enabled = optional(bool)
+ git = optional(object({
+ gcp_service_account_email = optional(string)
+ https_proxy = optional(string)
+ policy_dir = optional(string)
+ secret_type = optional(string, "none")
+ sync_branch = optional(string)
+ sync_repo = optional(string)
+ sync_rev = optional(string)
+ sync_wait_secs = optional(number)
+ }))
+ }))
+ }))
+ })
+ default = null
+ nullable = true
+}
+
+variable "location" {
+ description = "GKE hub location, will also be used for the membership location."
+ type = string
+ default = null
+ nullable = true
+}
+
variable "project_id" {
description = "GKE hub project ID."
type = string
diff --git a/tests/modules/gke_hub/examples/full.yaml b/tests/modules/gke_hub/examples/full.yaml
index 586bb815c..903069b1a 100644
--- a/tests/modules/gke_hub/examples/full.yaml
+++ b/tests/modules/gke_hub/examples/full.yaml
@@ -72,6 +72,7 @@ values:
enable_shielded_nodes: false
enable_tpu: false
fleet: []
+ in_transit_encryption_config: null
initial_node_count: 1
location: europe-west1
logging_config:
@@ -96,6 +97,7 @@ values:
managed_prometheus:
- enabled: true
name: cluster-1
+ network_performance_config: []
network_policy: []
node_config:
- advanced_machine_features: []
@@ -124,6 +126,14 @@ values:
storage_pools: null
tags: null
taint: []
+ node_pool_auto_config:
+ - linux_node_config:
+ - {}
+ network_tags:
+ - tags: []
+ node_kubelet_config:
+ - insecure_kubelet_readonly_port_enabled: 'TRUE'
+ resource_manager_tags: null
node_pool_defaults:
- node_config_defaults:
- containerd_config: []
@@ -192,7 +202,7 @@ values:
feature: configmanagement
location: global
membership: cluster-1
- membership_location: null
+ membership_location: europe-west1
mesh: []
policycontroller: []
project: gkehub-test
@@ -206,7 +216,7 @@ values:
- gke_cluster:
- {}
labels: null
- location: global
+ location: europe-west1
membership_id: cluster-1
project: gkehub-test
terraform_labels:
@@ -321,6 +331,7 @@ values:
name: network
network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL
network_profile: null
+ params: []
project: gkehub-test
routing_mode: GLOBAL
timeouts: null