diff --git a/autogen/main/cluster.tf.tmpl b/autogen/main/cluster.tf.tmpl index 5a9f63f6ba..ab5d52fbde 100644 --- a/autogen/main/cluster.tf.tmpl +++ b/autogen/main/cluster.tf.tmpl @@ -69,7 +69,7 @@ resource "google_container_cluster" "primary" { disabled = var.disable_default_snat } {% endif %} - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null {% if beta_cluster and autopilot_cluster != true %} dynamic "cluster_telemetry" { diff --git a/cluster.tf b/cluster.tf index cebee0167a..fd49dc15a3 100644 --- a/cluster.tf +++ b/cluster.tf @@ -50,7 +50,7 @@ resource "google_container_cluster" "primary" { subnetwork = "projects/${local.network_project_id}/regions/${local.region}/subnetworks/${var.subnetwork}" - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null logging_service = var.logging_service monitoring_service = var.monitoring_service diff --git a/examples/safer_cluster/README.md b/examples/safer_cluster/README.md index 556008e953..6f06b81710 100644 --- a/examples/safer_cluster/README.md +++ b/examples/safer_cluster/README.md @@ -17,6 +17,7 @@ This example illustrates how to instantiate the opinionated Safer Cluster module | ca\_certificate | The cluster ca certificate (base64 encoded) | | client\_token | The bearer token for auth | | cluster\_name | Cluster name | +| explicit\_k8s\_version | Explicit version used for cluster creation | | kubernetes\_endpoint | The cluster endpoint | | location | n/a | | master\_kubernetes\_version | Kubernetes version of the master | diff --git a/examples/safer_cluster/main.tf b/examples/safer_cluster/main.tf index d6de0cd279..a2c8ef8290 100644 --- a/examples/safer_cluster/main.tf +++ b/examples/safer_cluster/main.tf @@ -38,6 +38,18 @@ provider "kubernetes" { cluster_ca_certificate = base64decode(module.gke.ca_certificate) } +// A random valid k8s version is retrived +// to specify as an explicit version. +data "google_container_engine_versions" "current" { + project = var.project_id + location = var.region +} + +resource "random_shuffle" "version" { + input = data.google_container_engine_versions.current.valid_master_versions + result_count = 1 +} + module "gke" { source = "../../modules/safer-cluster/" project_id = var.project_id @@ -51,6 +63,8 @@ module "gke" { master_ipv4_cidr_block = "172.16.0.0/28" add_cluster_firewall_rules = true firewall_inbound_ports = ["9443", "15017"] + kubernetes_version = random_shuffle.version.result[0] + release_channel = "UNSPECIFIED" master_authorized_networks = [ { diff --git a/examples/safer_cluster/outputs.tf b/examples/safer_cluster/outputs.tf index d2f9706f02..d511b2c48e 100644 --- a/examples/safer_cluster/outputs.tf +++ b/examples/safer_cluster/outputs.tf @@ -74,3 +74,8 @@ output "project_id" { description = "The project ID the cluster is in" value = var.project_id } + +output "explicit_k8s_version" { + description = "Explicit version used for cluster creation" + value = random_shuffle.version.result[0] +} diff --git a/examples/safer_cluster/versions.tf b/examples/safer_cluster/versions.tf index 2d448a4b78..60030dba28 100644 --- a/examples/safer_cluster/versions.tf +++ b/examples/safer_cluster/versions.tf @@ -29,7 +29,8 @@ terraform { source = "hashicorp/kubernetes" } random = { - source = "hashicorp/random" + source = "hashicorp/random" + version = "~> 3.0" } } } diff --git a/modules/beta-autopilot-private-cluster/cluster.tf b/modules/beta-autopilot-private-cluster/cluster.tf index 551de2fac2..b86d2185dc 100644 --- a/modules/beta-autopilot-private-cluster/cluster.tf +++ b/modules/beta-autopilot-private-cluster/cluster.tf @@ -51,7 +51,7 @@ resource "google_container_cluster" "primary" { default_snat_status { disabled = var.disable_default_snat } - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null logging_service = var.logging_service monitoring_service = var.monitoring_service diff --git a/modules/beta-autopilot-public-cluster/cluster.tf b/modules/beta-autopilot-public-cluster/cluster.tf index 5faebd7065..a0357381ac 100644 --- a/modules/beta-autopilot-public-cluster/cluster.tf +++ b/modules/beta-autopilot-public-cluster/cluster.tf @@ -51,7 +51,7 @@ resource "google_container_cluster" "primary" { default_snat_status { disabled = var.disable_default_snat } - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null logging_service = var.logging_service monitoring_service = var.monitoring_service diff --git a/modules/beta-private-cluster-update-variant/cluster.tf b/modules/beta-private-cluster-update-variant/cluster.tf index 802ef2f223..e62c1398ad 100644 --- a/modules/beta-private-cluster-update-variant/cluster.tf +++ b/modules/beta-private-cluster-update-variant/cluster.tf @@ -59,7 +59,7 @@ resource "google_container_cluster" "primary" { default_snat_status { disabled = var.disable_default_snat } - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null dynamic "cluster_telemetry" { for_each = local.cluster_telemetry_type_is_set ? [1] : [] diff --git a/modules/beta-private-cluster/cluster.tf b/modules/beta-private-cluster/cluster.tf index 8d64e2d42e..1f1f805a0d 100644 --- a/modules/beta-private-cluster/cluster.tf +++ b/modules/beta-private-cluster/cluster.tf @@ -59,7 +59,7 @@ resource "google_container_cluster" "primary" { default_snat_status { disabled = var.disable_default_snat } - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null dynamic "cluster_telemetry" { for_each = local.cluster_telemetry_type_is_set ? [1] : [] diff --git a/modules/beta-public-cluster-update-variant/cluster.tf b/modules/beta-public-cluster-update-variant/cluster.tf index 731002cd3c..4eea77247b 100644 --- a/modules/beta-public-cluster-update-variant/cluster.tf +++ b/modules/beta-public-cluster-update-variant/cluster.tf @@ -59,7 +59,7 @@ resource "google_container_cluster" "primary" { default_snat_status { disabled = var.disable_default_snat } - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null dynamic "cluster_telemetry" { for_each = local.cluster_telemetry_type_is_set ? [1] : [] diff --git a/modules/beta-public-cluster/cluster.tf b/modules/beta-public-cluster/cluster.tf index 9d22602e5f..729947509c 100644 --- a/modules/beta-public-cluster/cluster.tf +++ b/modules/beta-public-cluster/cluster.tf @@ -59,7 +59,7 @@ resource "google_container_cluster" "primary" { default_snat_status { disabled = var.disable_default_snat } - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null dynamic "cluster_telemetry" { for_each = local.cluster_telemetry_type_is_set ? [1] : [] diff --git a/modules/private-cluster-update-variant/cluster.tf b/modules/private-cluster-update-variant/cluster.tf index b0cfb538b2..ae9e57ae50 100644 --- a/modules/private-cluster-update-variant/cluster.tf +++ b/modules/private-cluster-update-variant/cluster.tf @@ -50,7 +50,7 @@ resource "google_container_cluster" "primary" { subnetwork = "projects/${local.network_project_id}/regions/${local.region}/subnetworks/${var.subnetwork}" - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null logging_service = var.logging_service monitoring_service = var.monitoring_service diff --git a/modules/private-cluster/cluster.tf b/modules/private-cluster/cluster.tf index 460b85d7b7..e4540e64fe 100644 --- a/modules/private-cluster/cluster.tf +++ b/modules/private-cluster/cluster.tf @@ -50,7 +50,7 @@ resource "google_container_cluster" "primary" { subnetwork = "projects/${local.network_project_id}/regions/${local.region}/subnetworks/${var.subnetwork}" - min_master_version = var.release_channel != null ? null : local.master_version + min_master_version = var.release_channel == null || var.release_channel == "UNSPECIFIED" ? local.master_version : null logging_service = var.logging_service monitoring_service = var.monitoring_service diff --git a/test/fixtures/safer_cluster/outputs.tf b/test/fixtures/safer_cluster/outputs.tf index 8948896e1b..11c97a05c7 100644 --- a/test/fixtures/safer_cluster/outputs.tf +++ b/test/fixtures/safer_cluster/outputs.tf @@ -55,3 +55,7 @@ output "service_account" { description = "The service account to default running nodes as if not overridden in `node_pools`." value = module.example.service_account } + +output "explicit_k8s_version" { + value = module.example.explicit_k8s_version +} diff --git a/test/integration/safer_cluster/controls/gcloud.rb b/test/integration/safer_cluster/controls/gcloud.rb index 9faae675ca..1525ab6694 100644 --- a/test/integration/safer_cluster/controls/gcloud.rb +++ b/test/integration/safer_cluster/controls/gcloud.rb @@ -15,6 +15,7 @@ project_id = attribute('project_id') location = attribute('location') cluster_name = attribute('cluster_name') +explicit_version = attribute('explicit_k8s_version') control "gcloud" do title "Google Compute Engine GKE configuration" @@ -35,6 +36,11 @@ expect(data['status']).to eq 'RUNNING' end + it "has expected explicit version" do + expect(data['currentMasterVersion']).to eq explicit_version + expect(data['currentNodeVersion']).to eq explicit_version + end + it "is regional" do expect(data['location']).to match(/^.*[1-9]$/) end