From d6cb39062cc6ecc2f86af463afd883d1fd780657 Mon Sep 17 00:00:00 2001 From: Ghaleb Al-Habian Date: Wed, 3 Jan 2024 11:27:47 -0500 Subject: [PATCH] feat: dual stack (IPV4_IPV6) support (#1818) Co-authored-by: Jonathan Meyers Co-authored-by: Jonathan Meyers Co-authored-by: Bharath KKB Co-authored-by: Ghaleb Co-authored-by: Ghaleb Al-Habian Co-authored-by: Andrew Peabody --- .kitchen.yml | 7 + README.md | 1 + autogen/main/cluster.tf.tmpl | 1 + autogen/main/variables.tf.tmpl | 6 + cluster.tf | 1 + examples/simple_regional_with_ipv6/README.md | 45 ++++ examples/simple_regional_with_ipv6/main.tf | 45 ++++ examples/simple_regional_with_ipv6/outputs.tf | 35 ++++ .../simple_regional_with_ipv6/test_outputs.tf | 63 ++++++ .../simple_regional_with_ipv6/variables.tf | 52 +++++ .../simple_regional_with_ipv6/versions.tf | 27 +++ examples/simple_zonal_with_acm/acm.tf | 2 +- .../beta-autopilot-private-cluster/README.md | 1 + .../beta-autopilot-private-cluster/cluster.tf | 1 + .../variables.tf | 6 + .../beta-autopilot-public-cluster/README.md | 1 + .../beta-autopilot-public-cluster/cluster.tf | 1 + .../variables.tf | 6 + .../README.md | 1 + .../cluster.tf | 1 + .../variables.tf | 6 + modules/beta-private-cluster/README.md | 1 + modules/beta-private-cluster/cluster.tf | 1 + modules/beta-private-cluster/variables.tf | 6 + .../README.md | 1 + .../cluster.tf | 1 + .../variables.tf | 6 + modules/beta-public-cluster/README.md | 1 + modules/beta-public-cluster/cluster.tf | 1 + modules/beta-public-cluster/variables.tf | 6 + .../private-cluster-update-variant/README.md | 1 + .../private-cluster-update-variant/cluster.tf | 1 + .../variables.tf | 6 + modules/private-cluster/README.md | 1 + modules/private-cluster/cluster.tf | 1 + modules/private-cluster/variables.tf | 6 + .../simple_regional_with_ipv6/example.tf | 34 ++++ .../simple_regional_with_ipv6/network.tf | 50 +++++ .../simple_regional_with_ipv6/outputs.tf | 85 ++++++++ .../simple_regional_with_ipv6/variables.tf | 47 +++++ .../controls/gcloud.rb | 192 ++++++++++++++++++ .../simple_regional_with_ipv6/inspec.yml | 31 +++ variables.tf | 6 + 43 files changed, 793 insertions(+), 1 deletion(-) create mode 100644 examples/simple_regional_with_ipv6/README.md create mode 100644 examples/simple_regional_with_ipv6/main.tf create mode 100644 examples/simple_regional_with_ipv6/outputs.tf create mode 100755 examples/simple_regional_with_ipv6/test_outputs.tf create mode 100644 examples/simple_regional_with_ipv6/variables.tf create mode 100644 examples/simple_regional_with_ipv6/versions.tf create mode 100644 test/fixtures/simple_regional_with_ipv6/example.tf create mode 100644 test/fixtures/simple_regional_with_ipv6/network.tf create mode 100644 test/fixtures/simple_regional_with_ipv6/outputs.tf create mode 100644 test/fixtures/simple_regional_with_ipv6/variables.tf create mode 100644 test/integration/simple_regional_with_ipv6/controls/gcloud.rb create mode 100644 test/integration/simple_regional_with_ipv6/inspec.yml diff --git a/.kitchen.yml b/.kitchen.yml index a48a53aca..68fd13b68 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -87,6 +87,13 @@ suites: systems: - name: simple_regional_with_gateway_api backend: local + - name: "simple_regional_with_ipv6" + driver: + root_module_directory: test/fixtures/simple_regional_with_ipv6 + verifier: + systems: + - name: simple_regional_with_ipv6 + backend: local - name: "simple_regional_with_kubeconfig" driver: root_module_directory: test/fixtures/simple_regional_with_kubeconfig diff --git a/README.md b/README.md index 8668b4998..0075dcdde 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/autogen/main/cluster.tf.tmpl b/autogen/main/cluster.tf.tmpl index 459f4f712..61d6e1077 100644 --- a/autogen/main/cluster.tf.tmpl +++ b/autogen/main/cluster.tf.tmpl @@ -360,6 +360,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/autogen/main/variables.tf.tmpl b/autogen/main/variables.tf.tmpl index d97f8b4ee..060731e29 100644 --- a/autogen/main/variables.tf.tmpl +++ b/autogen/main/variables.tf.tmpl @@ -150,6 +150,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + {% if autopilot_cluster != true %} variable "node_pools" { type = list(map(any)) diff --git a/cluster.tf b/cluster.tf index 3f8c070a6..3429442a9 100644 --- a/cluster.tf +++ b/cluster.tf @@ -232,6 +232,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/examples/simple_regional_with_ipv6/README.md b/examples/simple_regional_with_ipv6/README.md new file mode 100644 index 000000000..e0442d420 --- /dev/null +++ b/examples/simple_regional_with_ipv6/README.md @@ -0,0 +1,45 @@ +# Simple Regional Cluster + +This example illustrates how to create a simple cluster. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| cluster\_name\_suffix | A suffix to append to the default cluster name | `string` | `""` | no | +| compute\_engine\_service\_account | Service account to associate to the nodes in the cluster | `any` | n/a | yes | +| ip\_range\_pods | The secondary ip range to use for pods | `any` | n/a | yes | +| ip\_range\_services | The secondary ip range to use for services | `any` | n/a | yes | +| network | The VPC network to host the cluster in | `any` | n/a | yes | +| project\_id | The project ID to host the cluster in | `any` | n/a | yes | +| region | The region to host the cluster in | `any` | n/a | yes | +| stack\_type | The stack type | `any` | n/a | yes | +| subnetwork | The subnetwork to host the cluster in | `any` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| ca\_certificate | n/a | +| client\_token | n/a | +| cluster\_name | Cluster name | +| ip\_range\_pods | The secondary IP range used for pods | +| ip\_range\_services | The secondary IP range used for services | +| kubernetes\_endpoint | n/a | +| location | n/a | +| master\_kubernetes\_version | The master Kubernetes version | +| network | n/a | +| project\_id | n/a | +| region | n/a | +| service\_account | The default service account used for running nodes. | +| subnetwork | n/a | +| zones | List of zones in which the cluster resides | + + + +To provision this example, run the following from within this directory: +- `terraform init` to get the plugins +- `terraform plan` to see the infrastructure plan +- `terraform apply` to apply the infrastructure build +- `terraform destroy` to destroy the built infrastructure diff --git a/examples/simple_regional_with_ipv6/main.tf b/examples/simple_regional_with_ipv6/main.tf new file mode 100644 index 000000000..59831f93c --- /dev/null +++ b/examples/simple_regional_with_ipv6/main.tf @@ -0,0 +1,45 @@ +/** + * Copyright 2018 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 { + cluster_type = "simple-regional-ipv6" +} + +data "google_client_config" "default" {} + +provider "kubernetes" { + host = "https://${module.gke.endpoint}" + token = data.google_client_config.default.access_token + cluster_ca_certificate = base64decode(module.gke.ca_certificate) +} + +module "gke" { + source = "../../" + project_id = var.project_id + name = "${local.cluster_type}-cluster${var.cluster_name_suffix}" + regional = true + region = var.region + network = var.network + subnetwork = var.subnetwork + ip_range_pods = var.ip_range_pods + ip_range_services = var.ip_range_services + stack_type = var.stack_type + create_service_account = false + service_account = var.compute_engine_service_account + enable_cost_allocation = true + datapath_provider = "ADVANCED_DATAPATH" + deletion_protection = false +} diff --git a/examples/simple_regional_with_ipv6/outputs.tf b/examples/simple_regional_with_ipv6/outputs.tf new file mode 100644 index 000000000..01a13147c --- /dev/null +++ b/examples/simple_regional_with_ipv6/outputs.tf @@ -0,0 +1,35 @@ +/** + * Copyright 2018 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. + */ + +output "kubernetes_endpoint" { + sensitive = true + value = module.gke.endpoint +} + +output "client_token" { + sensitive = true + value = base64encode(data.google_client_config.default.access_token) +} + +output "ca_certificate" { + value = module.gke.ca_certificate +} + +output "service_account" { + description = "The default service account used for running nodes." + value = module.gke.service_account +} + diff --git a/examples/simple_regional_with_ipv6/test_outputs.tf b/examples/simple_regional_with_ipv6/test_outputs.tf new file mode 100755 index 000000000..a0bc9a28f --- /dev/null +++ b/examples/simple_regional_with_ipv6/test_outputs.tf @@ -0,0 +1,63 @@ +/** + * Copyright 2020 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. + */ + +// These outputs are used to test the module with kitchen-terraform +// They do not need to be included in real-world uses of this module + +output "project_id" { + value = var.project_id +} + +output "region" { + value = module.gke.region +} + +output "cluster_name" { + description = "Cluster name" + value = module.gke.name +} + +output "network" { + value = var.network +} + +output "subnetwork" { + value = var.subnetwork +} + +output "location" { + value = module.gke.location +} + +output "ip_range_pods" { + description = "The secondary IP range used for pods" + value = var.ip_range_pods +} + +output "ip_range_services" { + description = "The secondary IP range used for services" + value = var.ip_range_services +} + +output "zones" { + description = "List of zones in which the cluster resides" + value = module.gke.zones +} + +output "master_kubernetes_version" { + description = "The master Kubernetes version" + value = module.gke.master_version +} diff --git a/examples/simple_regional_with_ipv6/variables.tf b/examples/simple_regional_with_ipv6/variables.tf new file mode 100644 index 000000000..d71793347 --- /dev/null +++ b/examples/simple_regional_with_ipv6/variables.tf @@ -0,0 +1,52 @@ +/** + * Copyright 2018 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. + */ + +variable "project_id" { + description = "The project ID to host the cluster in" +} + +variable "cluster_name_suffix" { + description = "A suffix to append to the default cluster name" + default = "" +} + +variable "region" { + description = "The region to host the cluster in" +} + +variable "network" { + description = "The VPC network to host the cluster in" +} + +variable "subnetwork" { + description = "The subnetwork to host the cluster in" +} + +variable "ip_range_pods" { + description = "The secondary ip range to use for pods" +} + +variable "ip_range_services" { + description = "The secondary ip range to use for services" +} + +variable "stack_type" { + description = "The stack type" +} + +variable "compute_engine_service_account" { + description = "Service account to associate to the nodes in the cluster" +} diff --git a/examples/simple_regional_with_ipv6/versions.tf b/examples/simple_regional_with_ipv6/versions.tf new file mode 100644 index 000000000..61934a306 --- /dev/null +++ b/examples/simple_regional_with_ipv6/versions.tf @@ -0,0 +1,27 @@ +/** + * Copyright 2021 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. + */ + +terraform { + required_providers { + google = { + source = "hashicorp/google" + } + kubernetes = { + source = "hashicorp/kubernetes" + } + } + required_version = ">= 0.13" +} diff --git a/examples/simple_zonal_with_acm/acm.tf b/examples/simple_zonal_with_acm/acm.tf index 010df6a0f..2d2f70a69 100644 --- a/examples/simple_zonal_with_acm/acm.tf +++ b/examples/simple_zonal_with_acm/acm.tf @@ -30,7 +30,7 @@ module "acm" { secret_type = "ssh" - policy_bundles = ["https://github.com/GoogleCloudPlatform/acm-policy-controller-library/bundles/policy-essentials-v2022?ref=981cdf31878b886b53decdade23d8f76e80140fc"] + policy_bundles = ["https://github.com/GoogleCloudPlatform/gke-policy-library/bundles/policy-essentials-v2022?ref=7a5f87d7e1a2f63582505d14c2c90f496bcf263d"] create_metrics_gcp_sa = true } diff --git a/modules/beta-autopilot-private-cluster/README.md b/modules/beta-autopilot-private-cluster/README.md index 0065139e5..3881493c2 100644 --- a/modules/beta-autopilot-private-cluster/README.md +++ b/modules/beta-autopilot-private-cluster/README.md @@ -135,6 +135,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/beta-autopilot-private-cluster/cluster.tf b/modules/beta-autopilot-private-cluster/cluster.tf index f73640869..539b17378 100644 --- a/modules/beta-autopilot-private-cluster/cluster.tf +++ b/modules/beta-autopilot-private-cluster/cluster.tf @@ -155,6 +155,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/beta-autopilot-private-cluster/variables.tf b/modules/beta-autopilot-private-cluster/variables.tf index 4bb85fac2..373fa527a 100644 --- a/modules/beta-autopilot-private-cluster/variables.tf +++ b/modules/beta-autopilot-private-cluster/variables.tf @@ -142,6 +142,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "enable_cost_allocation" { type = bool diff --git a/modules/beta-autopilot-public-cluster/README.md b/modules/beta-autopilot-public-cluster/README.md index e80fb4b92..7b93e80d9 100644 --- a/modules/beta-autopilot-public-cluster/README.md +++ b/modules/beta-autopilot-public-cluster/README.md @@ -124,6 +124,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/beta-autopilot-public-cluster/cluster.tf b/modules/beta-autopilot-public-cluster/cluster.tf index 7e0bccf5b..2c9bf25fc 100644 --- a/modules/beta-autopilot-public-cluster/cluster.tf +++ b/modules/beta-autopilot-public-cluster/cluster.tf @@ -155,6 +155,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/beta-autopilot-public-cluster/variables.tf b/modules/beta-autopilot-public-cluster/variables.tf index cadce988a..2c5679d00 100644 --- a/modules/beta-autopilot-public-cluster/variables.tf +++ b/modules/beta-autopilot-public-cluster/variables.tf @@ -142,6 +142,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "enable_cost_allocation" { type = bool diff --git a/modules/beta-private-cluster-update-variant/README.md b/modules/beta-private-cluster-update-variant/README.md index ce955dc88..176188b9d 100644 --- a/modules/beta-private-cluster-update-variant/README.md +++ b/modules/beta-private-cluster-update-variant/README.md @@ -274,6 +274,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/beta-private-cluster-update-variant/cluster.tf b/modules/beta-private-cluster-update-variant/cluster.tf index c07a41aa1..e211c69bf 100644 --- a/modules/beta-private-cluster-update-variant/cluster.tf +++ b/modules/beta-private-cluster-update-variant/cluster.tf @@ -290,6 +290,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/beta-private-cluster-update-variant/variables.tf b/modules/beta-private-cluster-update-variant/variables.tf index b4e79f3c3..5c18f1472 100644 --- a/modules/beta-private-cluster-update-variant/variables.tf +++ b/modules/beta-private-cluster-update-variant/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools" diff --git a/modules/beta-private-cluster/README.md b/modules/beta-private-cluster/README.md index 5e6b8f4d7..63c404851 100644 --- a/modules/beta-private-cluster/README.md +++ b/modules/beta-private-cluster/README.md @@ -252,6 +252,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/beta-private-cluster/cluster.tf b/modules/beta-private-cluster/cluster.tf index 830e70a93..e8d40bb54 100644 --- a/modules/beta-private-cluster/cluster.tf +++ b/modules/beta-private-cluster/cluster.tf @@ -290,6 +290,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/beta-private-cluster/variables.tf b/modules/beta-private-cluster/variables.tf index b4e79f3c3..5c18f1472 100644 --- a/modules/beta-private-cluster/variables.tf +++ b/modules/beta-private-cluster/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools" diff --git a/modules/beta-public-cluster-update-variant/README.md b/modules/beta-public-cluster-update-variant/README.md index 1596ee9f6..d091fcba9 100644 --- a/modules/beta-public-cluster-update-variant/README.md +++ b/modules/beta-public-cluster-update-variant/README.md @@ -263,6 +263,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/beta-public-cluster-update-variant/cluster.tf b/modules/beta-public-cluster-update-variant/cluster.tf index d0671e557..5752bbaee 100644 --- a/modules/beta-public-cluster-update-variant/cluster.tf +++ b/modules/beta-public-cluster-update-variant/cluster.tf @@ -290,6 +290,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/beta-public-cluster-update-variant/variables.tf b/modules/beta-public-cluster-update-variant/variables.tf index 653adb351..e6f3eab0e 100644 --- a/modules/beta-public-cluster-update-variant/variables.tf +++ b/modules/beta-public-cluster-update-variant/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools" diff --git a/modules/beta-public-cluster/README.md b/modules/beta-public-cluster/README.md index ddd7dd4c7..c022ab248 100644 --- a/modules/beta-public-cluster/README.md +++ b/modules/beta-public-cluster/README.md @@ -241,6 +241,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/beta-public-cluster/cluster.tf b/modules/beta-public-cluster/cluster.tf index f757f769d..f64bae3fd 100644 --- a/modules/beta-public-cluster/cluster.tf +++ b/modules/beta-public-cluster/cluster.tf @@ -290,6 +290,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/beta-public-cluster/variables.tf b/modules/beta-public-cluster/variables.tf index 653adb351..e6f3eab0e 100644 --- a/modules/beta-public-cluster/variables.tf +++ b/modules/beta-public-cluster/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools" diff --git a/modules/private-cluster-update-variant/README.md b/modules/private-cluster-update-variant/README.md index 608f8a120..4e2d0a90f 100644 --- a/modules/private-cluster-update-variant/README.md +++ b/modules/private-cluster-update-variant/README.md @@ -255,6 +255,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/private-cluster-update-variant/cluster.tf b/modules/private-cluster-update-variant/cluster.tf index a6bbfa9b5..210a883ad 100644 --- a/modules/private-cluster-update-variant/cluster.tf +++ b/modules/private-cluster-update-variant/cluster.tf @@ -232,6 +232,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/private-cluster-update-variant/variables.tf b/modules/private-cluster-update-variant/variables.tf index c593f7b3e..2f3de8bc6 100644 --- a/modules/private-cluster-update-variant/variables.tf +++ b/modules/private-cluster-update-variant/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools" diff --git a/modules/private-cluster/README.md b/modules/private-cluster/README.md index cbc62c36d..2daf73c43 100644 --- a/modules/private-cluster/README.md +++ b/modules/private-cluster/README.md @@ -233,6 +233,7 @@ Then perform the following commands on the root folder: | service\_external\_ips | Whether external ips specified by a service will be allowed in this cluster | `bool` | `false` | no | | shadow\_firewall\_rules\_log\_config | The log\_config for shadow firewall rules. You can set this variable to `null` to disable logging. |
object({
metadata = string
})
|
{
"metadata": "INCLUDE_ALL_METADATA"
}
| no | | shadow\_firewall\_rules\_priority | The firewall priority of GKE shadow firewall rules. The priority should be less than default firewall, which is 1000. | `number` | `999` | no | +| stack\_type | The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`. | `string` | `"IPV4"` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | `map(list(string))` | `{}` | no | | subnetwork | The subnetwork to host the cluster in (required) | `string` | n/a | yes | | timeouts | Timeout for cluster operations. | `map(string)` | `{}` | no | diff --git a/modules/private-cluster/cluster.tf b/modules/private-cluster/cluster.tf index e8eefa20d..097fc722b 100644 --- a/modules/private-cluster/cluster.tf +++ b/modules/private-cluster/cluster.tf @@ -232,6 +232,7 @@ resource "google_container_cluster" "primary" { pod_range_names = var.additional_ip_range_pods } } + stack_type = var.stack_type } maintenance_policy { diff --git a/modules/private-cluster/variables.tf b/modules/private-cluster/variables.tf index c593f7b3e..2f3de8bc6 100644 --- a/modules/private-cluster/variables.tf +++ b/modules/private-cluster/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools" diff --git a/test/fixtures/simple_regional_with_ipv6/example.tf b/test/fixtures/simple_regional_with_ipv6/example.tf new file mode 100644 index 000000000..f03848a8e --- /dev/null +++ b/test/fixtures/simple_regional_with_ipv6/example.tf @@ -0,0 +1,34 @@ +/** + * Copyright 2018 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 { + cluster_index = 1 +} + +module "example" { + source = "../../../examples/simple_regional_with_ipv6" + + project_id = var.project_ids[local.cluster_index] + cluster_name_suffix = "-${random_string.suffix.result}" + region = var.region + network = google_compute_network.main.name + subnetwork = google_compute_subnetwork.main.name + ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name + ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name + stack_type = "IPV4_IPV6" + compute_engine_service_account = var.compute_engine_service_accounts[local.cluster_index] + +} diff --git a/test/fixtures/simple_regional_with_ipv6/network.tf b/test/fixtures/simple_regional_with_ipv6/network.tf new file mode 100644 index 000000000..0a260d36f --- /dev/null +++ b/test/fixtures/simple_regional_with_ipv6/network.tf @@ -0,0 +1,50 @@ +/** + * Copyright 2018 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. + */ + +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +provider "google" { + project = var.project_ids[local.cluster_index] +} + +resource "google_compute_network" "main" { + name = "cft-gke-test-${random_string.suffix.result}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "main" { + name = "cft-gke-test-${random_string.suffix.result}" + ip_cidr_range = "10.0.0.0/17" + region = var.region + network = google_compute_network.main.self_link + stack_type = "IPV4_IPV6" + ipv6_access_type = "EXTERNAL" + + secondary_ip_range { + range_name = "cft-gke-test-pods-${random_string.suffix.result}" + ip_cidr_range = "192.168.0.0/18" + } + + secondary_ip_range { + range_name = "cft-gke-test-services-${random_string.suffix.result}" + ip_cidr_range = "192.168.64.0/18" + } +} + diff --git a/test/fixtures/simple_regional_with_ipv6/outputs.tf b/test/fixtures/simple_regional_with_ipv6/outputs.tf new file mode 100644 index 000000000..a62317bf6 --- /dev/null +++ b/test/fixtures/simple_regional_with_ipv6/outputs.tf @@ -0,0 +1,85 @@ +/** + * Copyright 2018 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. + */ + +output "project_id" { + value = module.example.project_id +} + +output "region" { + value = module.example.region +} + +output "cluster_name" { + description = "Cluster name" + value = module.example.cluster_name +} + +output "network" { + value = google_compute_network.main.name +} + +output "subnetwork" { + value = google_compute_subnetwork.main.name +} + +output "location" { + value = module.example.location +} + +output "ip_range_pods" { + description = "The secondary IP range used for pods" + value = google_compute_subnetwork.main.secondary_ip_range[0].range_name +} + +output "ip_range_services" { + description = "The secondary IP range used for services" + value = google_compute_subnetwork.main.secondary_ip_range[1].range_name +} + +output "zones" { + description = "List of zones in which the cluster resides" + value = module.example.zones +} + +output "master_kubernetes_version" { + description = "The master Kubernetes version" + value = module.example.master_kubernetes_version +} + +output "kubernetes_endpoint" { + sensitive = true + value = module.example.kubernetes_endpoint +} + +output "client_token" { + sensitive = true + value = module.example.client_token +} + +output "ca_certificate" { + description = "The cluster CA certificate" + value = module.example.ca_certificate + sensitive = true +} + +output "service_account" { + description = "The service account to default running nodes as if not overridden in `node_pools`." + value = module.example.service_account +} + +output "registry_project_ids" { + value = var.registry_project_ids +} diff --git a/test/fixtures/simple_regional_with_ipv6/variables.tf b/test/fixtures/simple_regional_with_ipv6/variables.tf new file mode 100644 index 000000000..8cf5823b2 --- /dev/null +++ b/test/fixtures/simple_regional_with_ipv6/variables.tf @@ -0,0 +1,47 @@ +/** + * Copyright 2018 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. + */ + +variable "project_ids" { + type = list(string) + description = "The GCP projects to use for integration tests" +} + +variable "region" { + description = "The GCP region to create and test resources in" + default = "us-central1" +} + +variable "zones" { + type = list(string) + description = "The GCP zones to create and test resources in, for applicable tests" + default = ["us-central1-a", "us-central1-b", "us-central1-c"] +} + +variable "compute_engine_service_accounts" { + type = list(string) + description = "The email addresses of the service account to associate with the GKE cluster" +} + +variable "registry_project_ids" { + description = "Projects to use for granting access to GCR registries, if requested" + type = list(string) +} + +variable "kubernetes_version" { + type = string + description = "The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region." + default = "latest" +} diff --git a/test/integration/simple_regional_with_ipv6/controls/gcloud.rb b/test/integration/simple_regional_with_ipv6/controls/gcloud.rb new file mode 100644 index 000000000..6b3e65e3c --- /dev/null +++ b/test/integration/simple_regional_with_ipv6/controls/gcloud.rb @@ -0,0 +1,192 @@ +# Copyright 2019 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 +# +# https://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. + +project_id = attribute('project_id') +location = attribute('location') +cluster_name = attribute('cluster_name') + +control "gcloud" do + title "Google Compute Engine GKE configuration" + describe command("gcloud --project=#{project_id} container clusters --zone=#{location} describe #{cluster_name} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:data) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + + describe "cluster" do + it "is running" do + expect(data['status']).to eq 'RUNNING' + end + + it "is regional" do + expect(data['location']).to match(/^.*[1-9]$/) + end + + it "uses public nodes and master endpoint" do + expect(data['privateClusterConfig']['enablePrivateEndpoint']).to eq nil + expect(data['privateClusterConfig']['enablePrivateNodes']).to eq nil + end + + it "has the expected addon settings" do + expect(data['addonsConfig']).to include( + "horizontalPodAutoscaling" => {}, + "httpLoadBalancing" => {}, + "kubernetesDashboard" => { + "disabled" => true, + }, + "networkPolicyConfig" => { + "disabled" => true, + }, + ) + end + + it "has dual stack enabled" do + expect(data['ipAllocationPolicy']).to include( + "stackType" => "IPV4_IPV6", + ) + end + + it "has the expected databaseEncryption config" do + expect(data['databaseEncryption']).to eq({ + "state" => 'DECRYPTED', + }) + end + + it "has the expected shieldedNodes config" do + expect(data['shieldedNodes']).to eq({ + "enabled" => true, + }) + end + + end + + describe "default node pool" do + let(:default_node_pool) { data['nodePools'].select { |p| p['name'] == "default-pool" }.first } + + it "exists" do + expect(data['nodePools']).to include( + including( + "name" => "default-pool", + ) + ) + end + end + + describe "node pool" do + let(:node_pools) { data['nodePools'].reject { |p| p['name'] == "default-pool" } } + + it "has autoscaling enabled" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "enabled" => true, + ), + ) + ) + end + + it "has the expected minimum node count" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "minNodeCount" => 1, + ), + ) + ) + end + + it "has the expected maximum node count" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "maxNodeCount" => 100, + ), + ) + ) + end + + it "is the expected machine type" do + expect(node_pools).to include( + including( + "config" => including( + "machineType" => "e2-medium", + ), + ) + ) + end + + it "has the expected disk size" do + expect(node_pools).to include( + including( + "config" => including( + "diskSizeGb" => 100, + ), + ) + ) + end + + it "has the expected labels" do + expect(node_pools).to include( + including( + "config" => including( + "labels" => including( + "cluster_name" => cluster_name, + "node_pool" => "default-node-pool", + ), + ), + ) + ) + end + + it "has the expected network tags" do + expect(node_pools).to include( + including( + "config" => including( + "tags" => match_array([ + "gke-#{cluster_name}", + "gke-#{cluster_name}-default-node-pool", + ]), + ), + ) + ) + end + + it "has autorepair enabled" do + expect(node_pools).to include( + including( + "management" => including( + "autoRepair" => true, + ), + ) + ) + end + + it "has autoupgrade enabled" do + expect(node_pools).to include( + including( + "management" => including( + "autoUpgrade" => true, + ), + ) + ) + end + end + end +end diff --git a/test/integration/simple_regional_with_ipv6/inspec.yml b/test/integration/simple_regional_with_ipv6/inspec.yml new file mode 100644 index 000000000..e91bbc6ca --- /dev/null +++ b/test/integration/simple_regional_with_ipv6/inspec.yml @@ -0,0 +1,31 @@ +# Copyright 2021 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. + +name: simple_regional_with_gateway_api +attributes: + - name: project_id + required: true + type: string + - name: location + required: true + type: string + - name: cluster_name + required: true + type: string + - name: kubernetes_endpoint + required: true + type: string + - name: client_token + required: true + type: string diff --git a/variables.tf b/variables.tf index a67db04b3..5a6c4b16b 100644 --- a/variables.tf +++ b/variables.tf @@ -148,6 +148,12 @@ variable "ip_range_services" { description = "The _name_ of the secondary subnet range to use for services" } +variable "stack_type" { + type = string + description = "The stack type to use for this cluster. Either `IPV4` or `IPV4_IPV6`. Defaults to `IPV4`." + default = "IPV4" +} + variable "node_pools" { type = list(map(any)) description = "List of maps containing node pools"