Merge branch 'maunope/network-dashboards-updates' of https://github.com/maunope/cloud-foundation-fabric into maunope/network-dashboards-updates

This commit is contained in:
Maurizio Noseda Pedraglio 2022-10-10 15:54:47 +02:00
commit 3b259a90bb
122 changed files with 1478 additions and 973 deletions

View File

@ -37,7 +37,7 @@ jobs:
- name: Set up Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.3
terraform_version: 1.3.2
- name: Install dependencies
run: |

View File

@ -48,10 +48,18 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
terraform_wrapper: false
# avoid conflicts with user-installed providers on local machines
- name: Pin provider versions
run: |
sed -i 's/>=\(.*# tftest\)/=\1/g' default-versions.tf
find -name versions.tf -exec cp default-versions.tf {} \;
for f in $(find . -name versions.tf); do
sed -i 's/>=\(.*# tftest\)/=\1/g' $f;
done
- name: Run tests on documentation examples
id: pytest
@ -76,15 +84,17 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Set up Terraform
uses: hashicorp/setup-terraform@v1
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
terraform_wrapper: false
# avoid conflicts with user-installed providers on local machines
- name: Pin provider versions
run: |
sed -i 's/>=\(.*# tftest\)/=\1/g' default-versions.tf
find -name versions.tf -exec cp default-versions.tf {} \;
for f in $(find . -name versions.tf); do
sed -i 's/>=\(.*# tftest\)/=\1/g' $f;
done
- name: Run tests environments
id: pytest
@ -109,15 +119,17 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Set up Terraform
uses: hashicorp/setup-terraform@v1
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
terraform_wrapper: false
# avoid conflicts with user-installed providers on local machines
- name: Pin provider versions
run: |
sed -i 's/>=\(.*# tftest\)/=\1/g' default-versions.tf
find -name versions.tf -exec cp default-versions.tf {} \;
for f in $(find . -name versions.tf); do
sed -i 's/>=\(.*# tftest\)/=\1/g' $f;
done
- name: Run tests modules
id: pytest
@ -142,15 +154,17 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Set up Terraform
uses: hashicorp/setup-terraform@v1
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
terraform_wrapper: false
# avoid conflicts with user-installed providers on local machines
- name: Pin provider versions
run: |
sed -i 's/>=\(.*# tftest\)/=\1/g' default-versions.tf
find -name versions.tf -exec cp default-versions.tf {} \;
for f in $(find . -name versions.tf); do
sed -i 's/>=\(.*# tftest\)/=\1/g' $f;
done
- name: Run tests on FAST stages
id: pytest

View File

@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file.
### BLUEPRINTS
- [[#868](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/868)] **incompatible change:** Refactor GKE module for Terraform 1.3 ([ludoo](https://github.com/ludoo)) <!-- 2022-10-10 07:38:21+00:00 -->
- [[#818](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/818)] Example wordpress ([skalolazka](https://github.com/skalolazka)) <!-- 2022-10-07 14:24:38+00:00 -->
- [[#861](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/861)] Leverage new shared VPC project config defaults across the repo ([juliocc](https://github.com/juliocc)) <!-- 2022-10-07 07:50:43+00:00 -->
- [[#854](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/854)] Added an example of a Nginx reverse proxy cluster using RMIGs ([rosmo](https://github.com/rosmo)) <!-- 2022-10-04 13:49:44+00:00 -->
- [[#850](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/850)] Made sample alert creation optional ([maunope](https://github.com/maunope)) <!-- 2022-09-30 10:08:37+00:00 -->
@ -21,10 +23,14 @@ All notable changes to this project will be documented in this file.
### DOCUMENTATION
- [[#863](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/863)] Fabric vs CFT doc ([ludoo](https://github.com/ludoo)) <!-- 2022-10-07 12:47:51+00:00 -->
- [[#806](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/806)] Companion Guide ([ajlopezn](https://github.com/ajlopezn)) <!-- 2022-09-12 07:11:03+00:00 -->
### FAST
- [[#868](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/868)] **incompatible change:** Refactor GKE module for Terraform 1.3 ([ludoo](https://github.com/ludoo)) <!-- 2022-10-10 07:38:21+00:00 -->
- [[#867](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/867)] FAST: Replace NVAs in 02-networking-nva with COS-based VMs ([sruffilli](https://github.com/sruffilli)) <!-- 2022-10-10 07:16:29+00:00 -->
- [[#865](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/865)] Enable FAST 00-cicd provider test ([ludoo](https://github.com/ludoo)) <!-- 2022-10-07 11:20:57+00:00 -->
- [[#861](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/861)] Leverage new shared VPC project config defaults across the repo ([juliocc](https://github.com/juliocc)) <!-- 2022-10-07 07:50:43+00:00 -->
- [[#858](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/858)] Default gcp-support to gcp-devops ([juliocc](https://github.com/juliocc)) <!-- 2022-10-06 12:58:26+00:00 -->
- [[#842](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/842)] Comment redundant role in bootstrap stage, align IAM.md files, improve IAM tool ([ludoo](https://github.com/ludoo)) <!-- 2022-09-29 06:30:02+00:00 -->
@ -35,6 +41,9 @@ All notable changes to this project will be documented in this file.
### MODULES
- [[#868](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/868)] **incompatible change:** Refactor GKE module for Terraform 1.3 ([ludoo](https://github.com/ludoo)) <!-- 2022-10-10 07:38:21+00:00 -->
- [[#866](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/866)] Update ipprefix_by_netmask.sh in nva module ([sruffilli](https://github.com/sruffilli)) <!-- 2022-10-09 15:26:54+00:00 -->
- [[#860](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/860)] **incompatible change:** Refactor compute-vm for Terraform 1.3 ([ludoo](https://github.com/ludoo)) <!-- 2022-10-07 08:53:53+00:00 -->
- [[#861](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/861)] Leverage new shared VPC project config defaults across the repo ([juliocc](https://github.com/juliocc)) <!-- 2022-10-07 07:50:43+00:00 -->
- [[#859](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/859)] Make project shared VPC fields optional ([juliocc](https://github.com/juliocc)) <!-- 2022-10-06 14:18:01+00:00 -->
- [[#853](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/853)] Fixes NVA issue when health checks are not enabled ([sruffilli](https://github.com/sruffilli)) <!-- 2022-10-04 05:55:10+00:00 -->
@ -54,6 +63,8 @@ All notable changes to this project will be documented in this file.
### TOOLS
- [[#865](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/865)] Enable FAST 00-cicd provider test ([ludoo](https://github.com/ludoo)) <!-- 2022-10-07 11:20:57+00:00 -->
- [[#864](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/864)] **incompatible change:** Bump terraform required version ([ludoo](https://github.com/ludoo)) <!-- 2022-10-07 10:51:56+00:00 -->
- [[#842](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/842)] Comment redundant role in bootstrap stage, align IAM.md files, improve IAM tool ([ludoo](https://github.com/ludoo)) <!-- 2022-09-29 06:30:02+00:00 -->
- [[#811](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/811)] Fix changelog generator ([ludoo](https://github.com/ludoo)) <!-- 2022-09-13 09:41:29+00:00 -->
- [[#810](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/810)] Fully recursive e2e test runner for examples ([juliocc](https://github.com/juliocc)) <!-- 2022-09-12 12:35:46+00:00 -->

170
FABRIC-AND-CFT.md Normal file
View File

@ -0,0 +1,170 @@
# Cloud Foundation Fabric and Cloud Foundation Toolkit
This page highlights the main differences (both technical and philosophical) between Cloud Foundation Fabric and Cloud Foundation Toolkit for end users, to guide them in their decision making process for identifying the best suite of modules for their use cases.
## Cloud Foundation Fabric (a.k.a Fabric, this repo)
Fabric is a collection of Terraform modules and end to end examples meant to be cloned as a single unit and used as is for fast prototyping or decomposed and modified for usage in organizations.
## Cloud Foundation Toolkit (a.k.a CFT)
CFT is a collection of Terraform modules and examples with opinionated GCP best practices implemented as individual modules for gradual adoption and off the shelf usage in organizations.
## Third-party reviews
* [Google Cloud Landing Zone Comparison](https://www.meshcloud.io/2022/09/09/gcp-landing-zone-comparison/) by Meshcloud.
## Key Differences
<table>
<tr>
<td>
</td>
<td><strong>Fabric</strong>
</td>
<td><strong>CFT</strong>
</td>
</tr>
<tr>
<td><strong>Target User</strong>
</td>
<td>Organizations interested in forking, maintaining and customizing Terraform modules.
</td>
<td>Organizations interested in using opinionated, prebuilt Terraform modules.
</td>
</tr>
<tr>
<td><strong>Configuration</strong>
</td>
<td>Less opinionated allowing end users higher flexibility.
</td>
<td>Opinionated by default, end users may need to fork if it does not meet their use case.
</td>
</tr>
<tr>
<td><strong>Extensibility</strong>
</td>
<td>Built with extensibility in mind catering to fork and use patterns. Modules are often lightweight and easy to adopt / tailor to specific use cases.
</td>
<td>Not built with fork and use extensibility, caters to off the shelf consumption.
</td>
</tr>
<tr>
<td><strong>Config customization</strong>
</td>
<td>Prefer customization using variables via objects, tight variable space.
</td>
<td>Prefer customization using variables via primitives.
</td>
</tr>
<tr>
<td><strong>Examples</strong>
</td>
<td>Thorough examples for individual modules, and end to end examples composing multiple modules covering a wide variety of use cases from foundations to solutions.
</td>
<td>Examples for a module mostly focus on that individual module. \
\
Composition is often not shown in examples but in other modules built using smaller modules.
</td>
</tr>
<tr>
<td><strong>Resources</strong>
</td>
<td>Leaner modules wrapping resources.
</td>
<td>Heavier root modules that often compose leaner sub modules wrapping resources.
</td>
</tr>
<tr>
<td><strong>Resource grouping</strong>
</td>
<td>Generally grouped by logical entities.
</td>
<td>Generally grouped by products/product areas.
</td>
</tr>
<tr>
<td><strong>Release Cadence</strong>
</td>
<td>Modules versioned and released together.
</td>
<td>Modules versioned and released individually.
</td>
</tr>
<tr>
<td><strong>Individual module usage</strong>
</td>
<td>Individual modules consumed directly using Git as a module source.
<p>
For production usage, we encourage customers to “fork and own” their own repository.
</td>
<td>Individual repositories consumed via the Terraform registry.
<p>
For production/airgapped usage, customers may also mirror modules to a private registry.
</td>
</tr>
<tr>
<td><strong>Factories</strong>
</td>
<td>Fabric implements several "factories" in modules, where users can drive or automate Terraform via YAML files (projects, subnetworks, firewalls, etc.).
</td>
<td>
</td>
</tr>
<tr>
<td><strong>Organizational adoption</strong>
</td>
<td>Mono repo cloned into an organizational VCS (or catalog) and separated into individual modules for internal consumption.
</td>
<td>Individual repos forked (for air gap) or wrapping upstream sources to create individual modules for internal consumption.
</td>
</tr>
<tr>
<td><strong>Distribution</strong>
</td>
<td>Distributed via Git/GitHub.
</td>
<td>Distributed via Git/GitHub and Terraform Registry.
</td>
</tr>
<tr>
<td><strong>Testing</strong>
</td>
<td>Every PR performs unit tests on modules, examples, and documentation snippets by evaluating a Terraform plan via Python <a href="https://pypi.org/project/tftest/">tftest</a> library.
</td>
<td>Every PR performs full end-to-end deployment with integration tests using the blueprint test framework.
</td>
</tr>
</table>
## Similarities
* Both collections of modules are designed with stable interfaces that work well together with other modules in their ecosystem.
* Both collections of modules require minimal variables and provide defaults.
* Both collections of modules are well tested and documented with information about usage, code snippets and provide information about variables and outputs.
## Should you choose Fabric or CFT?
> You/Your organization is knowledgeable in Terraform and interested in forking and owning a collection of modules.
Fabric is a better choice as it bootstraps you with a collection of modules out of the box that can be customized exactly to fit your organization needs.
> You/Your organization is getting started with Terraform and interested in GCP best practices out of the box.
CFT is a better choice as it allows you to directly reference specific modules from the registry and provide opinionated configuration by default.
> You/Your organization is looking to rapidly prototype some functionality on GCP.
Fabric is a better choice. Being a mono repo it allows you to get started quickly with all your source code in one place for easier debugging.
> You/Your organization has existing infrastructure and processes but want to start adopting IaC gradually.
CFT is designed to be modular and off the shelf, providing higher level abstractions to product groups which allows certain teams to adopt Terraform without maintenance burden while allowing others to follow existing practices.
## Using Fabric and CFT together
Even with all the above points, it may be hard to make a decision. While the modules may have different patterns and philosophies, it is often possible to bring the best of both worlds together. Here are some tips to follow:
* Since modules work well together within their ecosystem, select logical boundaries for using Fabric or CFT. For example use CFT for deploying resources within projects but use Fabric for managing project creation and IAM.
* Use strengths of each collection of modules to your advantage. Empower application teams to define their infrastructure as code using off the shelf CFT modules. Using Fabric, bootstrap your platform team with a collection of tailor built modules for your organization.
* Lean into module composition and dependency inversion that both Fabric and CFT modules follow. For example, you can create a GKE cluster using either [Fabric](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/modules/gke-cluster#gke-cluster-module) or [CFT](https://github.com/terraform-google-modules/terraform-google-kubernetes-engine) GKE module and then use either [Fabric](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/tree/master/modules/gke-hub#variables) or [CFT](https://github.com/terraform-google-modules/terraform-google-kubernetes-engine/tree/master/modules/fleet-membership) for setting up GKE Hub by passing in outputs from the GKE module.

View File

@ -13,7 +13,7 @@ This repository provides **end-to-end blueprints** and a **suite of Terraform mo
- reference [blueprints](./blueprints/) used to deep dive on network patterns or product features
- a comprehensive source of lean [modules](./modules/dns) that lend themselves well to changes
The whole repository is meant to be cloned as a single unit, and then forked into separate owned repositories to seed production usage, or used as-is and periodically updated as a complete toolkit for prototyping. You can read more on this approach in our [contributing guide](./CONTRIBUTING.md).
The whole repository is meant to be cloned as a single unit, and then forked into separate owned repositories to seed production usage, or used as-is and periodically updated as a complete toolkit for prototyping. You can read more on this approach in our [contributing guide](./CONTRIBUTING.md), and a comparison against similar toolkits [here](./FABRIC-AND-CFT.md).
## Organization blueprint (Fabric FAST)

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -83,21 +83,19 @@ module "nat" {
}
module "cluster" {
source = "../../../modules/gke-cluster"
project_id = module.project.project_id
name = "${local.prefix}cluster"
location = var.zone
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"]
secondary_range_pods = "pods"
secondary_range_services = "services"
source = "../../../modules/gke-cluster"
project_id = module.project.project_id
name = "${local.prefix}cluster"
location = var.zone
vpc_config = {
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"]
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = var.master_cidr_block
master_global_access = false
}
workload_identity = true
}
module "cluster_nodepool" {

View File

@ -133,30 +133,27 @@ module "mgmt_server" {
}
module "clusters" {
for_each = var.clusters_config
source = "../../../modules/gke-cluster"
project_id = module.fleet_project.project_id
name = each.key
location = var.region
network = module.svpc.self_link
subnetwork = module.svpc.subnet_self_links["${var.region}/subnet-${each.key}"]
secondary_range_pods = "pods"
secondary_range_services = "services"
for_each = var.clusters_config
source = "../../../modules/gke-cluster"
project_id = module.fleet_project.project_id
name = each.key
location = var.region
vpc_config = {
network = module.svpc.self_link
subnetwork = module.svpc.subnet_self_links["${var.region}/subnet-${each.key}"]
master_authorized_ranges = merge({
mgmt : var.mgmt_subnet_cidr_block
},
{ for key, config in var.clusters_config :
"pods-${key}" => config.pods_cidr_block if key != each.key
})
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = true
master_ipv4_cidr_block = each.value.master_cidr_block
master_global_access = true
}
master_authorized_ranges = merge({
mgmt : var.mgmt_subnet_cidr_block
},
{ for key, config in var.clusters_config :
"pods-${key}" => config.pods_cidr_block if key != each.key
})
enable_autopilot = false
release_channel = "REGULAR"
workload_identity = true
release_channel = "REGULAR"
labels = {
mesh_id = "proj-${module.fleet_project.number}"
}

View File

@ -24,93 +24,69 @@ locals {
}
module "gke-cluster" {
source = "../../../modules/gke-cluster"
for_each = local.clusters
name = each.key
project_id = module.gke-project-0.project_id
description = each.value.description
location = each.value.location
network = var.vpc_config.vpc_self_link
subnetwork = each.value.net.subnet
secondary_range_pods = each.value.net.pods
secondary_range_services = each.value.net.services
labels = each.value.labels
addons = {
cloudrun_config = each.value.overrides.cloudrun_config
dns_cache_config = true
http_load_balancing = true
gce_persistent_disk_csi_driver_config = true
horizontal_pod_autoscaling = true
config_connector_config = true
kalm_config = false
gcp_filestore_csi_driver_config = each.value.overrides.gcp_filestore_csi_driver_config
gke_backup_agent_config = false
# enable only if enable_dataplane_v2 is changed to false below
network_policy_config = false
istio_config = {
enabled = false
tls = false
source = "../../../modules/gke-cluster"
for_each = local.clusters
name = each.key
project_id = module.gke-project-0.project_id
description = each.value.description
location = each.value.location
vpc_config = {
network = var.vpc_config.vpc_self_link
subnetwork = each.value.net.subnet
secondary_range_names = {
pods = each.value.net.pods
services = each.value.net.services
}
master_authorized_ranges = each.value.overrides.master_authorized_ranges
}
labels = each.value.labels
enable_addons = {
cloudrun = each.value.overrides.cloudrun_config
config_connector = true
dns_cache = true
gce_persistent_disk_csi_driver = true
gcp_filestore_csi_driver = each.value.overrides.gcp_filestore_csi_driver_config
gke_backup_agent = false
horizontal_pod_autoscaling = true
http_load_balancing = true
}
enable_features = {
cloud_dns = var.dns_domain == null ? null : {
cluster_dns = "CLOUD_DNS"
cluster_dns_scope = "VPC_SCOPE"
cluster_dns_domain = "${each.key}.${var.dns_domain}"
}
database_encryption = (
each.value.overrides.database_encryption_key == null
? null
: {
state = "ENCRYPTED"
key_name = each.value.overrides.database_encryption_key
}
)
dataplane_v2 = true
groups_for_rbac = var.authenticator_security_group
intranode_visibility = true
pod_security_policy = each.value.overrides.pod_security_policy
resource_usage_export = {
dataset = module.gke-dataset-resource-usage.dataset_id
}
shielded_nodes = true
vertical_pod_autoscaling = each.value.overrides.vertical_pod_autoscaling
workload_identity = true
}
# change these here for all clusters if absolutely needed
authenticator_security_group = var.authenticator_security_group
enable_dataplane_v2 = true
enable_l4_ilb_subsetting = false
enable_intranode_visibility = true
enable_shielded_nodes = true
workload_identity = true
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = false
enable_private_endpoint = true
master_ipv4_cidr_block = each.value.net.master_range
master_global_access = true
}
dns_config = each.value.dns_domain == null ? null : {
cluster_dns = "CLOUD_DNS"
cluster_dns_scope = "VPC_SCOPE"
cluster_dns_domain = "${each.key}.${var.dns_domain}"
peering_config = var.peering_config == null ? null : {
export_routes = var.peering_config.export_routes
import_routes = var.peering_config.import_routes
project_id = var.vpc_config.host_project_id
}
}
logging_config = ["SYSTEM_COMPONENTS", "WORKLOADS"]
monitoring_config = ["SYSTEM_COMPONENTS", "WORKLOADS"]
peering_config = var.peering_config == null ? null : {
export_routes = var.peering_config.export_routes
import_routes = var.peering_config.import_routes
project_id = var.vpc_config.host_project_id
}
resource_usage_export_config = {
enabled = true
dataset = module.gke-dataset-resource-usage.dataset_id
}
# TODO: the attributes below are "primed" from project-level defaults
# in locals, merge defaults with cluster-level stuff
# TODO(jccb): change fabric module
database_encryption = (
each.value.overrides.database_encryption_key == null
? {
enabled = false
state = null
key_name = null
}
: {
enabled = true
state = "ENCRYPTED"
key_name = each.value.overrides.database_encryption_key
}
)
default_max_pods_per_node = each.value.overrides.max_pods_per_node
master_authorized_ranges = each.value.overrides.master_authorized_ranges
pod_security_policy = each.value.overrides.pod_security_policy
release_channel = each.value.overrides.release_channel
vertical_pod_autoscaling = each.value.overrides.vertical_pod_autoscaling
# dynamic "cluster_autoscaling" {
# for_each = each.value.cluster_autoscaling == null ? {} : { 1 = 1 }
# content {
# enabled = true
# cpu_min = each.value.cluster_autoscaling.cpu_min
# cpu_max = each.value.cluster_autoscaling.cpu_max
# memory_min = each.value.cluster_autoscaling.memory_min
# memory_max = each.value.cluster_autoscaling.memory_max
# }
# }
max_pods_per_node = each.value.overrides.max_pods_per_node
release_channel = each.value.overrides.release_channel
}

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -237,31 +237,29 @@ module "service-account-gce" {
################################################################################
module "cluster-1" {
source = "../../../modules/gke-cluster"
name = "${local.prefix}cluster-1"
project_id = module.project.project_id
location = "${var.region}-b"
network = module.vpc-spoke-2.self_link
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/${local.prefix}spoke-2-1"]
secondary_range_pods = "pods"
secondary_range_services = "services"
default_max_pods_per_node = 32
source = "../../../modules/gke-cluster"
name = "${local.prefix}cluster-1"
project_id = module.project.project_id
location = "${var.region}-b"
vpc_config = {
network = module.vpc-spoke-2.self_link
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/${local.prefix}spoke-2-1"]
master_authorized_ranges = {
for name, range in var.ip_ranges : name => range
}
}
max_pods_per_node = 32
labels = {
environment = "test"
}
master_authorized_ranges = {
for name, range in var.ip_ranges : name => range
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = true
master_ipv4_cidr_block = var.private_service_ranges.spoke-2-cluster-1
master_global_access = true
}
peering_config = {
export_routes = true
import_routes = false
project_id = null
peering_config = {
export_routes = true
import_routes = false
}
}
}

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -196,28 +196,27 @@ module "vm-bastion" {
################################################################################
module "cluster-1" {
source = "../../../modules/gke-cluster"
count = var.cluster_create ? 1 : 0
name = "cluster-1"
project_id = module.project-svc-gke.project_id
location = "${var.region}-b"
network = module.vpc-shared.self_link
subnetwork = module.vpc-shared.subnet_self_links["${var.region}/gke"]
secondary_range_pods = "pods"
secondary_range_services = "services"
default_max_pods_per_node = 32
labels = {
environment = "test"
}
master_authorized_ranges = {
internal-vms = var.ip_ranges.gce
source = "../../../modules/gke-cluster"
count = var.cluster_create ? 1 : 0
name = "cluster-1"
project_id = module.project-svc-gke.project_id
location = "${var.region}-b"
vpc_config = {
network = module.vpc-shared.self_link
subnetwork = module.vpc-shared.subnet_self_links["${var.region}/gke"]
master_authorized_ranges = {
internal-vms = var.ip_ranges.gce
}
}
max_pods_per_node = 32
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = true
master_ipv4_cidr_block = var.private_service_ranges.cluster-1
master_global_access = true
}
labels = {
environment = "test"
}
}
module "cluster-1-nodepool-1" {

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -0,0 +1,139 @@
# Wordpress deployment on Cloud Run
43% of the Web is built on Wordpress. Because of its simplicity and versatility, Wordpress can be used for internal websites as well as customer facing e-commerce platforms in small to large businesses, while still offering security.
This repository contains the necessary Terraform files to deploy a functioning new Wordpress website exposed to the public internet with minimal technical overhead.
This architecture can be used for the following use cases and more:
* Blog
* Intranet / internal Wiki
* E-commerce platform
# Architecture
![Wordpress on Cloud Run](images/architecture.png "Wordpress on Cloud Run")
The main components that are deployed in this architecture are the following (you can learn about them by following the hyperlinks):
* [Cloud Run](https://cloud.google.com/run): serverless PaaS offering to host containers for web-oriented applications, while offering security, scalability and easy versioning
* [Cloud SQL](https://cloud.google.com/sql): Managed solution for SQL databases
* [VPC Serverless Connector](https://cloud.google.com/vpc/docs/serverless-vpc-access): Solution to access the CloudSQL VPC from Cloud Run, using only internal IP addresses
# Setup
## Prerequisites
### Setting up the project for the deployment
This example will deploy all its resources into the project defined by the `project_id` variable. Please note that we assume this project already exists. However, if you provide the appropriate values to the `project_create` variable, the project will be created as part of the deployment.
If `project_create` is left to null, the identity performing the deployment needs the `owner` role on the project defined by the `project_id` variable. Otherwise, the identity performing the deployment needs `resourcemanager.projectCreator` on the resource hierarchy node specified by `project_create.parent` and `billing.user` on the billing account specified by `project_create.billing_account_id`.
## Deployment
### Step 0: Cloning the repository
If you want to deploy from your Cloud Shell, click on the image below, sign in if required and when the prompt appears, click on “confirm”.
[<p align="center"> <img alt="Open Cloudshell" width = "300px" src="images/button.png" /> </p>](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2Fcloud-foundation-fabric&cloudshell_print=cloud-shell-readme.txt&cloudshell_working_dir=blueprints%2Fthird-party-solutions%2Fwordpress)
Otherwise, in your console of choice:
``` {shell}
git clone https://github.com/GoogleCloudPlatform/cloud-foundation-fabric
```
Before you deploy the architecture, you will need at least the following information (for more precise configuration see the Variables section):
* The project ID.
* A Google Cloud Registry path to a Wordpress container image.
### Step 1: Add Wordpress image
In order to deploy the Wordpress service to Cloud Run, you need to store the [Wordpress image](https://hub.docker.com/r/bitnami/wordpress/) in Google Cloud Registry (GCR).
Make sure that the Google Container Registry API is enabled and run the following commands in your Cloud Shell environment with your `project_id` in place of the `MY_PROJECT` placeholder:
``` {shell}
docker pull bitnami/wordpress:6.0.2
docker tag bitnami/wordpress gcr.io/MY_PROJECT/wordpress
docker push gcr.io/MY_PROJECT/wordpress
```
**Note**: This example has been built for this particular Docker image. If you decide to use another one, this example might not work (or you can edit the variables in the Terraform files).
### Step 2: Prepare the variables
Once you have the required information, head back to your cloned repository. Make sure youre in the directory of this tutorial (where this README is in).
Configure the Terraform variables in your `terraform.tfvars` file. See [terraform.tfvars.sample](terraform.tfvars.sample) as starting point - just copy it to `terraform.tfvars` and edit the latter. See the variables documentation below.
**Notes**:
1. If you will want to change your admin password later on, please note that it will only work in the admin interface of Wordpress, but not with redeploying with Terraform, since Wordpress writes that password into the database upon installation and ignores the environment variables (that you can change with Terraform) after that.
2. If you have the [domain restriction org. policy](https://cloud.google.com/resource-manager/docs/organization-policy/restricting-domains) on your organization, you have to edit the `cloud_run_invoker` variable and give it a value that will be accepted in accordance to your policy.
### Step 3: Deploy resources
Initialize your Terraform environment and deploy the resources:
``` {shell}
terraform init
terraform apply
```
The resource creation will take a few minutes.
**Note**: you might get the following error (or a similar one):
``` {shell}
│ Error: resource is in failed state "Ready:False", message: Revision '...' is not ready and cannot serve traffic.│
```
You might try to reapply at this point, the Cloud Run service just needs several minutes.
### Step 4: Use the created resources
Upon completion, you will see the output with the values for the Cloud Run service and the user and password to access the `/admin` part of the website. You can also view it later with:
``` {shell}
terraform output
# or for the concrete variable:
terraform output cloud_run_service
```
1. Open your browser at the URL that you get with that last command, and you will see your Wordpress installation.
2. Add "/admin" in the end of the URL and log in to the admin interface, using the outputs "wp_user" and "wp_password".
## Cleaning up your environment
The easiest way to remove all the deployed resources is to run the following command in Cloud Shell:
``` {shell}
terraform destroy
```
The above command will delete the associated resources so there will be no billable charges made afterwards.
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [project_id](variables.tf#L72) | Project id, references existing project if `project_create` is null. | <code>string</code> | ✓ | |
| [wordpress_image](variables.tf#L83) | Image to run with Cloud Run, starts with \"gcr.io\" | <code>string</code> | ✓ | |
| [cloud_run_invoker](variables.tf#L18) | IAM member authorized to access the end-point (for example, 'user:YOUR_IAM_USER' for only you or 'allUsers' for everyone) | <code>string</code> | | <code>&#34;allUsers&#34;</code> |
| [cloudsql_password](variables.tf#L24) | CloudSQL password (will be randomly generated by default) | <code>string</code> | | <code>null</code> |
| [create_connector](variables.tf#L30) | Should a VPC serverless connector be created or not | <code>bool</code> | | <code>true</code> |
| [ip_ranges](variables.tf#L37) | CIDR blocks: VPC serverless connector, Private Service Access(PSA) for CloudSQL, CloudSQL VPC | <code title="object&#40;&#123;&#10; connector &#61; string&#10; psa &#61; string&#10; sql_vpc &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; connector &#61; &#34;10.8.0.0&#47;28&#34;&#10; psa &#61; &#34;10.60.0.0&#47;24&#34;&#10; sql_vpc &#61; &#34;10.0.0.0&#47;20&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [prefix](variables.tf#L51) | Unique prefix used for resource names. Not used for project if 'project_create' is null. | <code>string</code> | | <code>&#34;&#34;</code> |
| [principals](variables.tf#L57) | List of users to give rights to (CloudSQL admin, client and instanceUser, Logging admin, Service Account User and TokenCreator), eg 'user@domain.com'. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [project_create](variables.tf#L63) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object&#40;&#123;&#10; billing_account_id &#61; string&#10; parent &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [region](variables.tf#L77) | Region for the created resources | <code>string</code> | | <code>&#34;europe-west4&#34;</code> |
| [wordpress_password](variables.tf#L94) | Password for the Wordpress user (will be randomly generated by default) | <code>string</code> | | <code>null</code> |
| [wordpress_port](variables.tf#L88) | Port for the Wordpress image | <code>number</code> | | <code>8080</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| [cloud_run_service](outputs.tf#L17) | CloudRun service URL | ✓ |
| [cloudsql_password](outputs.tf#L23) | CloudSQL password | ✓ |
| [wp_password](outputs.tf#L34) | Wordpress user password | ✓ |
| [wp_user](outputs.tf#L29) | Wordpress username | |
<!-- END TFDOC -->

View File

@ -0,0 +1,70 @@
/**
* Copyright 2022 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_password" "cloudsql_password" {
length = 8
}
# create a VPC for CloudSQL
module "vpc" {
source = "../../../../modules/net-vpc"
project_id = module.project.project_id
name = "${local.prefix}sql-vpc"
subnets = [
{
ip_cidr_range = var.ip_ranges.sql_vpc
name = "subnet"
region = var.region
secondary_ip_range = {}
}
]
# Private Service Access
psa_config = {
ranges = {
cloud-sql = var.ip_ranges.psa
}
routes = null
}
}
# create a VPC connector for the ClouSQL VPC
resource "google_vpc_access_connector" "connector" {
count = var.create_connector ? 1 : 0
project = module.project.project_id
name = "${local.prefix}wp-connector"
region = var.region
ip_cidr_range = var.ip_ranges.connector
network = module.vpc.self_link
}
# Set up CloudSQL
module "cloudsql" {
source = "../../../../modules/cloudsql-instance"
project_id = module.project.project_id
network = module.vpc.self_link
name = "${local.prefix}mysql"
region = var.region
database_version = local.cloudsql_conf.database_version
tier = local.cloudsql_conf.tier
databases = [local.cloudsql_conf.db]
users = {
"${local.cloudsql_conf.user}" = "${local.cloudsql_conf.pass}"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,121 @@
/**
* Copyright 2022 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 {
all_principals_iam = [for k in var.principals : "user:${k}"]
cloudsql_conf = {
database_version = "MYSQL_8_0"
tier = "db-g1-small"
db = "wp-mysql"
user = "admin"
pass = var.cloudsql_password == null ? random_password.cloudsql_password.result : var.cloudsql_password
}
iam = {
# CloudSQL
"roles/cloudsql.admin" = local.all_principals_iam
"roles/cloudsql.client" = local.all_principals_iam
"roles/cloudsql.instanceUser" = local.all_principals_iam
# common roles
"roles/logging.admin" = local.all_principals_iam
"roles/iam.serviceAccountUser" = local.all_principals_iam
"roles/iam.serviceAccountTokenCreator" = local.all_principals_iam
}
connector = var.connector == null ? google_vpc_access_connector.connector.0.self_link : var.connector
prefix = var.prefix == null ? "" : "${var.prefix}-"
wp_user = "user"
wp_pass = var.wordpress_password == null ? random_password.wp_password.result : var.wordpress_password
}
# either create a project or set up the given one
module "project" {
source = "../../../../modules/project"
name = var.project_id
parent = try(var.project_create.parent, null)
billing_account = try(var.project_create.billing_account_id, null)
project_create = var.project_create != null
prefix = var.project_create == null ? null : var.prefix
iam = var.project_create != null ? local.iam : {}
iam_additive = var.project_create == null ? local.iam : {}
services = [
"run.googleapis.com",
"logging.googleapis.com",
"monitoring.googleapis.com",
"sqladmin.googleapis.com",
"sql-component.googleapis.com",
"vpcaccess.googleapis.com",
"servicenetworking.googleapis.com"
]
}
resource "random_password" "wp_password" {
length = 8
}
# create the Cloud Run service
module "cloud_run" {
source = "../../../../modules/cloud-run"
project_id = module.project.project_id
name = "${local.prefix}cr-wordpress"
region = var.region
containers = [{
image = var.wordpress_image
ports = [{
name = "http1"
protocol = null
container_port = var.wordpress_port
}]
options = {
command = null
args = null
env_from = null
# set up the database connection
env = {
"APACHE_HTTP_PORT_NUMBER" : var.wordpress_port
"WORDPRESS_DATABASE_HOST" : module.cloudsql.ip
"WORDPRESS_DATABASE_NAME" : local.cloudsql_conf.db
"WORDPRESS_DATABASE_USER" : local.cloudsql_conf.user
"WORDPRESS_DATABASE_PASSWORD" : local.cloudsql_conf.pass
"WORDPRESS_USERNAME" : local.wp_user
"WORDPRESS_PASSWORD" : local.wp_pass
}
}
resources = null
volume_mounts = null
}]
iam = {
"roles/run.invoker" : [var.cloud_run_invoker]
}
revision_annotations = {
autoscaling = {
min_scale = 1
max_scale = 2
}
# connect to CloudSQL
cloudsql_instances = [module.cloudsql.connection_name]
vpcaccess_connector = null
# allow all traffic
vpcaccess_egress = "all-traffic"
vpcaccess_connector = local.connector
}
ingress_settings = "all"
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2022 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 "cloud_run_service" {
description = "CloudRun service URL"
value = module.cloud_run.service.status[0].url
sensitive = true
}
output "cloudsql_password" {
description = "CloudSQL password"
value = local.cloudsql_conf.pass
sensitive = true
}
output "wp_user" {
description = "Wordpress username"
value = local.wp_user
}
output "wp_password" {
description = "Wordpress user password"
value = local.wp_pass
sensitive = true
}

View File

@ -0,0 +1,3 @@
prefix = "wp"
project_id = "my-wordpress-project"
wordpress_image = "gcr.io/my-wordpress-project/wordpress"

View File

@ -0,0 +1,104 @@
/**
* Copyright 2022 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.
*/
# Documentation: https://cloud.google.com/run/docs/securing/managing-access#making_a_service_public
variable "cloud_run_invoker" {
type = string
description = "IAM member authorized to access the end-point (for example, 'user:YOUR_IAM_USER' for only you or 'allUsers' for everyone)"
default = "allUsers"
}
variable "cloudsql_password" {
type = string
description = "CloudSQL password (will be randomly generated by default)"
default = null
}
variable "connector" {
type = string
description = "Existing VPC serverless connector to use if not creating a new one"
default = null
}
variable "create_connector" {
type = bool
description = "Should a VPC serverless connector be created or not"
default = true
}
# PSA: documentation: https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range
variable "ip_ranges" {
description = "CIDR blocks: VPC serverless connector, Private Service Access(PSA) for CloudSQL, CloudSQL VPC"
type = object({
connector = string
psa = string
sql_vpc = string
})
default = {
connector = "10.8.0.0/28"
psa = "10.60.0.0/24"
sql_vpc = "10.0.0.0/20"
}
}
variable "prefix" {
description = "Unique prefix used for resource names. Not used for project if 'project_create' is null."
type = string
default = ""
}
variable "principals" {
description = "List of users to give rights to (CloudSQL admin, client and instanceUser, Logging admin, Service Account User and TokenCreator), eg 'user@domain.com'."
type = list(string)
default = []
}
variable "project_create" {
description = "Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format."
type = object({
billing_account_id = string
parent = string
})
default = null
}
variable "project_id" {
description = "Project id, references existing project if `project_create` is null."
type = string
}
variable "region" {
type = string
description = "Region for the created resources"
default = "europe-west4"
}
variable "wordpress_image" {
type = string
description = "Image to run with Cloud Run, starts with \"gcr.io\""
}
variable "wordpress_port" {
type = number
description = "Port for the Wordpress image"
default = 8080
}
variable "wordpress_password" {
type = string
description = "Password for the Wordpress user (will be randomly generated by default)"
default = null
}

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"
@ -33,5 +33,3 @@ terraform {
version = ">= 3.16.1"
}
}

View File

@ -352,7 +352,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [landing.tf](./landing.tf) | Landing VPC and related resources. | <code>net-cloudnat</code> · <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>project</code> | |
| [main.tf](./main.tf) | Networking folder and hierarchical policy. | <code>folder</code> | |
| [monitoring.tf](./monitoring.tf) | Network monitoring dashboards. | | <code>google_monitoring_dashboard</code> |
| [nva.tf](./nva.tf) | None | <code>compute-mig</code> · <code>compute-vm</code> · <code>net-ilb</code> | |
| [nva.tf](./nva.tf) | None | <code>compute-mig</code> · <code>compute-vm</code> · <code>simple-nva</code> | |
| [outputs.tf](./outputs.tf) | Module outputs. | | <code>google_storage_bucket_object</code> · <code>local_file</code> |
| [spoke-dev.tf](./spoke-dev.tf) | Dev spoke VPC and related resources. | <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>net-vpc-peering</code> · <code>project</code> | <code>google_project_iam_binding</code> |
| [spoke-prod.tf](./spoke-prod.tf) | Production spoke VPC and related resources. | <code>net-vpc</code> · <code>net-vpc-firewall</code> · <code>net-vpc-peering</code> · <code>project</code> | <code>google_project_iam_binding</code> |

View File

@ -15,181 +15,97 @@
*/
locals {
_subnets = var.data_dir == null ? tomap({}) : {
for f in fileset("${var.data_dir}/subnets", "**/*.yaml") :
trimsuffix(basename(f), ".yaml") => yamldecode(file("${var.data_dir}/subnets/${f}"))
}
subnets = merge(
{ for k, v in local._subnets : "${k}-cidr" => v.ip_cidr_range },
{ for k, v in local._subnets : "${k}-gw" => cidrhost(v.ip_cidr_range, 1) }
)
}
# europe-west1
module "nva-template-ew1" {
source = "../../../modules/compute-vm"
project_id = module.landing-project.project_id
name = "nva-template"
zone = "europe-west1-b"
tags = ["nva"]
can_ip_forward = true
network_interfaces = [
# routing_config should be aligned to the NVA network interfaces - i.e.
# local.routing_config[0] sets up the first interface, and so on.
routing_config = [
{
network = module.landing-untrusted-vpc.self_link
subnetwork = module.landing-untrusted-vpc.subnet_self_links["europe-west1/landing-untrusted-default-ew1"]
name = "untrusted"
routes = [
var.custom_adv.gcp_landing_untrusted_ew1,
var.custom_adv.gcp_landing_untrusted_ew4,
]
},
{
network = module.landing-trusted-vpc.self_link
subnetwork = module.landing-trusted-vpc.subnet_self_links["europe-west1/landing-trusted-default-ew1"]
}
name = "trusted"
routes = [
var.custom_adv.gcp_dev_ew1,
var.custom_adv.gcp_dev_ew4,
var.custom_adv.gcp_landing_trusted_ew1,
var.custom_adv.gcp_landing_trusted_ew4,
var.custom_adv.gcp_prod_ew1,
var.custom_adv.gcp_prod_ew4,
]
},
]
boot_disk = {
image = "projects/debian-cloud/global/images/family/debian-10"
nva_locality = {
europe-west1-b = { region = "europe-west1", trigram = "ew1", zone = "b" },
europe-west1-c = { region = "europe-west1", trigram = "ew1", zone = "c" },
europe-west4-b = { region = "europe-west4", trigram = "ew4", zone = "b" },
europe-west4-c = { region = "europe-west4", trigram = "ew4", zone = "c" },
}
}
# NVA config
module "nva-cloud-config" {
source = "../../../modules/cloud-config-container/simple-nva"
enable_health_checks = true
network_interfaces = local.routing_config
}
module "nva-template" {
for_each = local.nva_locality
source = "../../../modules/compute-vm"
project_id = module.landing-project.project_id
name = "nva-template-${each.value.trigram}-${each.value.zone}"
zone = "${each.value.region}-${each.value.zone}"
instance_type = "e2-standard-2"
tags = ["nva"]
create_template = true
instance_type = "f1-micro"
options = {
spot = true
termination_action = "STOP"
}
metadata = {
startup-script = templatefile(
"${path.module}/data/nva-startup-script.tftpl",
{
dev-default-ew1-cidr = local.subnets.dev-default-ew1-cidr
dev-default-ew4-cidr = local.subnets.dev-default-ew4-cidr
gateway-trusted = local.subnets.landing-trusted-default-ew1-gw
gateway-untrusted = local.subnets.landing-untrusted-default-ew1-gw
landing-trusted-other-region = local.subnets.landing-trusted-default-ew4-cidr
landing-untrusted-other-region = local.subnets.landing-untrusted-default-ew4-cidr
onprem-main-cidr = var.onprem_cidr.main
prod-default-ew1-cidr = local.subnets.prod-default-ew1-cidr
prod-default-ew4-cidr = local.subnets.prod-default-ew4-cidr
}
)
}
}
module "nva-mig-ew1" {
source = "../../../modules/compute-mig"
project_id = module.landing-project.project_id
regional = true
location = "europe-west1"
name = "nva-ew1"
target_size = 2
auto_healing_policies = {
health_check = module.nva-mig-ew1.health_check.self_link
initial_delay_sec = 30
}
health_check_config = {
type = "tcp"
check = { port = 22 }
config = {}
logging = true
}
default_version = {
instance_template = module.nva-template-ew1.template.self_link
name = "default"
}
}
module "ilb-nva-untrusted-ew1" {
source = "../../../modules/net-ilb"
project_id = module.landing-project.project_id
region = "europe-west1"
name = "ilb-nva-untrusted-ew1"
service_label = var.prefix
global_access = true
network = module.landing-untrusted-vpc.self_link
subnetwork = module.landing-untrusted-vpc.subnet_self_links["europe-west1/landing-untrusted-default-ew1"]
backends = [{
failover = false
group = module.nva-mig-ew1.group_manager.instance_group
balancing_mode = "CONNECTION"
}]
health_check_config = {
type = "tcp", check = { port = 22 }, config = {}, logging = false
}
}
module "ilb-nva-trusted-ew1" {
source = "../../../modules/net-ilb"
project_id = module.landing-project.project_id
region = "europe-west1"
name = "ilb-nva-trusted-ew1"
service_label = var.prefix
global_access = true
network = module.landing-trusted-vpc.self_link
subnetwork = module.landing-trusted-vpc.subnet_self_links["europe-west1/landing-trusted-default-ew1"]
backends = [{
failover = false
group = module.nva-mig-ew1.group_manager.instance_group
balancing_mode = "CONNECTION"
}]
health_check_config = {
type = "tcp", check = { port = 22 }, config = {}, logging = false
}
}
# europe-west4
module "nva-template-ew4" {
source = "../../../modules/compute-vm"
project_id = module.landing-project.project_id
name = "nva-template"
zone = "europe-west4-a"
tags = ["nva"]
can_ip_forward = true
can_ip_forward = true
network_interfaces = [
{
network = module.landing-untrusted-vpc.self_link
subnetwork = module.landing-untrusted-vpc.subnet_self_links["europe-west4/landing-untrusted-default-ew4"]
subnetwork = module.landing-untrusted-vpc.subnet_self_links["${each.value.region}/landing-untrusted-default-${each.value.trigram}"]
nat = false
addresses = null
},
{
network = module.landing-trusted-vpc.self_link
subnetwork = module.landing-trusted-vpc.subnet_self_links["europe-west4/landing-trusted-default-ew4"]
subnetwork = module.landing-trusted-vpc.subnet_self_links["${each.value.region}/landing-trusted-default-${each.value.trigram}"]
nat = false
addresses = null
}
]
boot_disk = {
image = "projects/debian-cloud/global/images/family/debian-10"
type = "pd-balanced"
image = "projects/cos-cloud/global/images/family/cos-stable"
size = 10
type = "pd-balanced"
}
options = {
allow_stopping_for_update = true
deletion_protection = false
spot = true
termination_action = "STOP"
}
create_template = true
metadata = {
startup-script = templatefile(
"${path.module}/data/nva-startup-script.tftpl",
{
dev-default-ew1-cidr = local.subnets.dev-default-ew1-cidr
dev-default-ew4-cidr = local.subnets.dev-default-ew4-cidr
gateway-trusted = local.subnets.landing-trusted-default-ew4-gw
gateway-untrusted = local.subnets.landing-untrusted-default-ew4-gw
landing-trusted-other-region = local.subnets.landing-trusted-default-ew1-cidr
landing-untrusted-other-region = local.subnets.landing-untrusted-default-ew1-cidr
onprem-main-cidr = var.onprem_cidr.main
prod-default-ew1-cidr = local.subnets.prod-default-ew1-cidr
prod-default-ew4-cidr = local.subnets.prod-default-ew4-cidr
}
)
user-data = module.nva-cloud-config.cloud_config
}
}
module "nva-mig-ew4" {
module "nva-mig" {
for_each = local.nva_locality
source = "../../../modules/compute-mig"
project_id = module.landing-project.project_id
regional = true
location = "europe-west4"
name = "nva-ew4"
target_size = 2
auto_healing_policies = {
health_check = module.nva-mig-ew4.health_check.self_link
initial_delay_sec = 30
}
location = each.value.region
name = "nva-cos-${each.value.trigram}-${each.value.zone}"
target_size = 1
# FIXME: cycle
# auto_healing_policies = {
# health_check = module.nva-mig[each.key].health_check.self_link
# initial_delay_sec = 30
# }
health_check_config = {
type = "tcp"
check = { port = 22 }
@ -197,45 +113,51 @@ module "nva-mig-ew4" {
logging = true
}
default_version = {
instance_template = module.nva-template-ew4.template.self_link
instance_template = module.nva-template[each.key].template.self_link
name = "default"
}
}
module "ilb-nva-untrusted-ew4" {
module "ilb-nva-untrusted" {
for_each = { for l in local.nva_locality : l.region => l.trigram... }
source = "../../../modules/net-ilb"
project_id = module.landing-project.project_id
region = "europe-west4"
name = "ilb-nva-untrusted-ew4"
region = each.key
name = "nva-untrusted-${each.value.0}"
service_label = var.prefix
global_access = true
network = module.landing-untrusted-vpc.self_link
subnetwork = module.landing-untrusted-vpc.subnet_self_links["europe-west4/landing-untrusted-default-ew4"]
backends = [{
failover = false
group = module.nva-mig-ew4.group_manager.instance_group
balancing_mode = "CONNECTION"
}]
subnetwork = module.landing-untrusted-vpc.subnet_self_links["${each.key}/landing-untrusted-default-${each.value.0}"]
backends = [for key, _ in local.nva_locality :
{
failover = false
group = module.nva-mig[key].group_manager.instance_group
balancing_mode = "CONNECTION"
} if local.nva_locality[key].region == each.key]
health_check_config = {
type = "tcp", check = { port = 22 }, config = {}, logging = false
}
}
module "ilb-nva-trusted-ew4" {
module "ilb-nva-trusted" {
for_each = { for l in local.nva_locality : l.region => l.trigram... }
source = "../../../modules/net-ilb"
project_id = module.landing-project.project_id
region = "europe-west4"
name = "ilb-nva-trusted-ew4"
region = each.key
name = "nva-trusted-${each.value.0}"
service_label = var.prefix
global_access = true
network = module.landing-trusted-vpc.self_link
subnetwork = module.landing-trusted-vpc.subnet_self_links["europe-west4/landing-trusted-default-ew4"]
backends = [{
failover = false
group = module.nva-mig-ew4.group_manager.instance_group
balancing_mode = "CONNECTION"
}]
subnetwork = module.landing-trusted-vpc.subnet_self_links["${each.key}/landing-trusted-default-${each.value.0}"]
backends = [for key, _ in local.nva_locality :
{
failover = false
group = module.nva-mig[key].group_manager.instance_group
balancing_mode = "CONNECTION"
} if local.nva_locality[key].region == each.key]
health_check_config = {
type = "tcp", check = { port = 22 }, config = {}, logging = false
}
}

View File

@ -72,28 +72,28 @@ module "dev-spoke-vpc" {
priority = 1000
tags = ["ew1"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew1.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west1"].forwarding_rule_address
}
nva-ew4-to-ew4 = {
dest_range = "0.0.0.0/0"
priority = 1000
tags = ["ew4"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew4.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west4"].forwarding_rule_address
}
nva-ew1-to-ew4 = {
dest_range = "0.0.0.0/0"
priority = 1001
tags = ["ew1"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew4.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west4"].forwarding_rule_address
}
nva-ew4-to-ew1 = {
dest_range = "0.0.0.0/0"
priority = 1001
tags = ["ew4"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew1.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west1"].forwarding_rule_address
}
}
}

View File

@ -72,28 +72,28 @@ module "prod-spoke-vpc" {
priority = 1000
tags = ["ew1"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew1.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west1"].forwarding_rule_address
}
nva-ew4-to-ew4 = {
dest_range = "0.0.0.0/0"
priority = 1000
tags = ["ew4"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew4.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west4"].forwarding_rule_address
}
nva-ew1-to-ew4 = {
dest_range = "0.0.0.0/0"
priority = 1001
tags = ["ew1"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew4.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west4"].forwarding_rule_address
}
nva-ew4-to-ew1 = {
dest_range = "0.0.0.0/0"
priority = 1001
tags = ["ew4"]
next_hop_type = "ilb"
next_hop = module.ilb-nva-trusted-ew1.forwarding_rule_address
next_hop = module.ilb-nva-trusted["europe-west1"].forwarding_rule_address
}
}
}

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -1,4 +1,4 @@
# Google Cloud DNS Module
# Google Simple NVA Module
This module allows for the creation of a NVA (Network Virtual Appliance) to be used for experiments and as a stub for future appliances deployment.

View File

@ -15,7 +15,7 @@
# limitations under the License.
# https://stackoverflow.com/questions/50413579/bash-convert-netmask-in-cidr-notation
c=0 x=0$(printf '%o' $${1//./ })
c=0 x=0$(printf '%o' ${1//./ })
while [ $x -gt 0 ]; do
let c+=$((x % 2)) 'x>>=1'
done

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -8,20 +8,23 @@ This module allows simplified creation and management of GKE clusters and should
```hcl
module "cluster-1" {
source = "./fabric/modules/gke-cluster"
project_id = "myproject"
name = "cluster-1"
location = "europe-west1-b"
network = var.vpc.self_link
subnetwork = var.subnet.self_link
secondary_range_pods = "pods"
secondary_range_services = "services"
default_max_pods_per_node = 32
master_authorized_ranges = {
internal-vms = "10.0.0.0/8"
source = "./fabric/modules/gke-cluster"
project_id = "myproject"
name = "cluster-1"
location = "europe-west1-b"
vpc_config = {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
secondary_range_names = {
pods = "pods"
services = "services"
}
master_authorized_ranges = {
internal-vms = "10.0.0.0/8"
}
}
max_pods_per_node = 32
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = true
master_ipv4_cidr_block = "192.168.0.0/28"
master_global_access = false
@ -37,25 +40,30 @@ module "cluster-1" {
```hcl
module "cluster-1" {
source = "./fabric/modules/gke-cluster"
project_id = "myproject"
name = "cluster-1"
location = "europe-west1-b"
network = var.vpc.self_link
subnetwork = var.subnet.self_link
secondary_range_pods = "pods"
secondary_range_services = "services"
default_max_pods_per_node = 32
enable_dataplane_v2 = true
master_authorized_ranges = {
internal-vms = "10.0.0.0/8"
source = "./fabric/modules/gke-cluster"
project_id = "myproject"
name = "cluster-1"
location = "europe-west1-b"
vpc_config = {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
secondary_range_names = {
pods = "pods"
services = "services"
}
master_authorized_ranges = {
internal-vms = "10.0.0.0/8"
}
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = true
master_ipv4_cidr_block = "192.168.0.0/28"
master_global_access = false
}
enable_features = {
dataplane_v2 = true
workload_identity = true
}
labels = {
environment = "dev"
}
@ -68,44 +76,24 @@ module "cluster-1" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [location](variables.tf#L161) | Cluster zone or region. | <code>string</code> | ✓ | |
| [name](variables.tf#L228) | Cluster name. | <code>string</code> | ✓ | |
| [network](variables.tf#L233) | Name or self link of the VPC used for the cluster. Use the self link for Shared VPC. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L277) | Cluster project id. | <code>string</code> | ✓ | |
| [secondary_range_pods](variables.tf#L300) | Subnet secondary range name used for pods. | <code>string</code> | ✓ | |
| [secondary_range_services](variables.tf#L305) | Subnet secondary range name used for services. | <code>string</code> | ✓ | |
| [subnetwork](variables.tf#L310) | VPC subnetwork name or self link. | <code>string</code> | ✓ | |
| [addons](variables.tf#L17) | Addons enabled in the cluster (true means enabled). | <code title="object&#40;&#123;&#10; cloudrun_config &#61; bool&#10; dns_cache_config &#61; bool&#10; horizontal_pod_autoscaling &#61; bool&#10; http_load_balancing &#61; bool&#10; istio_config &#61; object&#40;&#123;&#10; enabled &#61; bool&#10; tls &#61; bool&#10; &#125;&#41;&#10; network_policy_config &#61; bool&#10; gce_persistent_disk_csi_driver_config &#61; bool&#10; gcp_filestore_csi_driver_config &#61; bool&#10; config_connector_config &#61; bool&#10; kalm_config &#61; bool&#10; gke_backup_agent_config &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; cloudrun_config &#61; false&#10; dns_cache_config &#61; false&#10; horizontal_pod_autoscaling &#61; true&#10; http_load_balancing &#61; true&#10; istio_config &#61; &#123;&#10; enabled &#61; false&#10; tls &#61; false&#10; &#125;&#10; network_policy_config &#61; false&#10; gce_persistent_disk_csi_driver_config &#61; false&#10; gcp_filestore_csi_driver_config &#61; false&#10; config_connector_config &#61; false&#10; kalm_config &#61; false&#10; gke_backup_agent_config &#61; false&#10;&#125;">&#123;&#8230;&#125;</code> |
| [authenticator_security_group](variables.tf#L53) | RBAC security group for Google Groups for GKE, format is gke-security-groups@yourdomain.com. | <code>string</code> | | <code>null</code> |
| [cluster_autoscaling](variables.tf#L59) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | <code title="object&#40;&#123;&#10; enabled &#61; bool&#10; cpu_min &#61; number&#10; cpu_max &#61; number&#10; memory_min &#61; number&#10; memory_max &#61; number&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; enabled &#61; false&#10; cpu_min &#61; 0&#10; cpu_max &#61; 0&#10; memory_min &#61; 0&#10; memory_max &#61; 0&#10;&#125;">&#123;&#8230;&#125;</code> |
| [database_encryption](variables.tf#L77) | Enable and configure GKE application-layer secrets encryption. | <code title="object&#40;&#123;&#10; enabled &#61; bool&#10; state &#61; string&#10; key_name &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; enabled &#61; false&#10; state &#61; &#34;DECRYPTED&#34;&#10; key_name &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [default_max_pods_per_node](variables.tf#L91) | Maximum number of pods per node in this cluster. | <code>number</code> | | <code>110</code> |
| [description](variables.tf#L97) | Cluster description. | <code>string</code> | | <code>null</code> |
| [dns_config](variables.tf#L103) | Configuration for Using Cloud DNS for GKE. | <code title="object&#40;&#123;&#10; cluster_dns &#61; string&#10; cluster_dns_scope &#61; string&#10; cluster_dns_domain &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [enable_autopilot](variables.tf#L113) | Create cluster in autopilot mode. With autopilot there's no need to create node-pools and some features are not supported (e.g. setting default_max_pods_per_node). | <code>bool</code> | | <code>false</code> |
| [enable_binary_authorization](variables.tf#L119) | Enable Google Binary Authorization. | <code>bool</code> | | <code>false</code> |
| [enable_dataplane_v2](variables.tf#L125) | Enable Dataplane V2 on the cluster, will disable network_policy addons config. | <code>bool</code> | | <code>false</code> |
| [enable_intranode_visibility](variables.tf#L131) | Enable intra-node visibility to make same node pod to pod traffic visible. | <code>bool</code> | | <code>null</code> |
| [enable_l4_ilb_subsetting](variables.tf#L137) | Enable L4ILB Subsetting. | <code>bool</code> | | <code>null</code> |
| [enable_shielded_nodes](variables.tf#L143) | Enable Shielded Nodes features on all nodes in this cluster. | <code>bool</code> | | <code>null</code> |
| [enable_tpu](variables.tf#L149) | Enable Cloud TPU resources in this cluster. | <code>bool</code> | | <code>null</code> |
| [labels](variables.tf#L155) | Cluster resource labels. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [logging_config](variables.tf#L166) | Logging configuration (enabled components). | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [logging_service](variables.tf#L172) | Logging service (disable with an empty string). | <code>string</code> | | <code>&#34;logging.googleapis.com&#47;kubernetes&#34;</code> |
| [maintenance_config](variables.tf#L178) | Maintenance window configuration. | <code title="object&#40;&#123;&#10; daily_maintenance_window &#61; object&#40;&#123;&#10; start_time &#61; string&#10; &#125;&#41;&#10; recurring_window &#61; object&#40;&#123;&#10; start_time &#61; string&#10; end_time &#61; string&#10; recurrence &#61; string&#10; &#125;&#41;&#10; maintenance_exclusion &#61; list&#40;object&#40;&#123;&#10; exclusion_name &#61; string&#10; start_time &#61; string&#10; end_time &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; daily_maintenance_window &#61; &#123;&#10; start_time &#61; &#34;03:00&#34;&#10; &#125;&#10; recurring_window &#61; null&#10; maintenance_exclusion &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [master_authorized_ranges](variables.tf#L204) | External Ip address ranges that can access the Kubernetes cluster master through HTTPS. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [min_master_version](variables.tf#L210) | Minimum version of the master, defaults to the version of the most recent official release. | <code>string</code> | | <code>null</code> |
| [monitoring_config](variables.tf#L216) | Monitoring configuration (enabled components). | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [monitoring_service](variables.tf#L222) | Monitoring service (disable with an empty string). | <code>string</code> | | <code>&#34;monitoring.googleapis.com&#47;kubernetes&#34;</code> |
| [node_locations](variables.tf#L238) | Zones in which the cluster's nodes are located. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [notification_config](variables.tf#L244) | GKE Cluster upgrade notifications via PubSub. | <code>bool</code> | | <code>false</code> |
| [peering_config](variables.tf#L250) | Configure peering with the master VPC for private clusters. | <code title="object&#40;&#123;&#10; export_routes &#61; bool&#10; import_routes &#61; bool&#10; project_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [pod_security_policy](variables.tf#L260) | Enable the PodSecurityPolicy feature. | <code>bool</code> | | <code>null</code> |
| [private_cluster_config](variables.tf#L266) | Enable and configure private cluster, private nodes must be true if used. | <code title="object&#40;&#123;&#10; enable_private_nodes &#61; bool&#10; enable_private_endpoint &#61; bool&#10; master_ipv4_cidr_block &#61; string&#10; master_global_access &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [release_channel](variables.tf#L282) | Release channel for GKE upgrades. | <code>string</code> | | <code>null</code> |
| [resource_usage_export_config](variables.tf#L288) | Configure the ResourceUsageExportConfig feature. | <code title="object&#40;&#123;&#10; enabled &#61; bool&#10; dataset &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; enabled &#61; null&#10; dataset &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [vertical_pod_autoscaling](variables.tf#L315) | Enable the Vertical Pod Autoscaling feature. | <code>bool</code> | | <code>null</code> |
| [workload_identity](variables.tf#L321) | Enable the Workload Identity feature. | <code>bool</code> | | <code>true</code> |
| [location](variables.tf#L118) | Cluster zone or region. | <code>string</code> | ✓ | |
| [name](variables.tf#L170) | Cluster name. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L197) | Cluster project id. | <code>string</code> | ✓ | |
| [vpc_config](variables.tf#L208) | VPC-level configuration. | <code title="object&#40;&#123;&#10; network &#61; string&#10; subnetwork &#61; string&#10; secondary_range_blocks &#61; optional&#40;object&#40;&#123;&#10; pods &#61; string&#10; services &#61; string&#10; &#125;&#41;, &#41;&#10; secondary_range_names &#61; optional&#40;object&#40;&#123;&#10; pods &#61; string&#10; services &#61; string&#10; &#125;&#41;, &#123; pods &#61; &#34;pods&#34;, services &#61; &#34;services&#34; &#125;&#41;&#10; master_authorized_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [cluster_autoscaling](variables.tf#L17) | Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler. | <code title="object&#40;&#123;&#10; auto_provisioning_defaults &#61; optional&#40;object&#40;&#123;&#10; boot_disk_kms_key &#61; optional&#40;string&#41;&#10; image_type &#61; optional&#40;string&#41;&#10; oauth_scopes &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_account &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; cpu_limits &#61; optional&#40;object&#40;&#123;&#10; min &#61; number&#10; max &#61; number&#10; &#125;&#41;&#41;&#10; mem_limits &#61; optional&#40;object&#40;&#123;&#10; min &#61; number&#10; max &#61; number&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [description](variables.tf#L38) | Cluster description. | <code>string</code> | | <code>null</code> |
| [enable_addons](variables.tf#L44) | Addons enabled in the cluster (true means enabled). | <code title="object&#40;&#123;&#10; cloudrun &#61; optional&#40;bool, false&#41;&#10; config_connector &#61; optional&#40;bool, false&#41;&#10; dns_cache &#61; optional&#40;bool, false&#41;&#10; gce_persistent_disk_csi_driver &#61; optional&#40;bool, false&#41;&#10; gcp_filestore_csi_driver &#61; optional&#40;bool, false&#41;&#10; gke_backup_agent &#61; optional&#40;bool, false&#41;&#10; horizontal_pod_autoscaling &#61; optional&#40;bool, false&#41;&#10; http_load_balancing &#61; optional&#40;bool, false&#41;&#10; istio &#61; optional&#40;object&#40;&#123;&#10; enable_tls &#61; bool&#10; &#125;&#41;&#41;&#10; kalm &#61; optional&#40;bool, false&#41;&#10; network_policy &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; horizontal_pod_autoscaling &#61; true&#10; http_load_balancing &#61; true&#10;&#125;">&#123;&#8230;&#125;</code> |
| [enable_features](variables.tf#L68) | Enable cluster-level features. Certain features allow configuration. | <code title="object&#40;&#123;&#10; autopilot &#61; optional&#40;bool, false&#41;&#10; binary_authorization &#61; optional&#40;bool, false&#41;&#10; cloud_dns &#61; optional&#40;object&#40;&#123;&#10; provider &#61; optional&#40;string&#41;&#10; scope &#61; optional&#40;string&#41;&#10; domain &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; database_encryption &#61; optional&#40;object&#40;&#123;&#10; state &#61; string&#10; key_name &#61; string&#10; &#125;&#41;&#41;&#10; dataplane_v2 &#61; optional&#40;bool, false&#41;&#10; groups_for_rbac &#61; optional&#40;string&#41;&#10; intranode_visibility &#61; optional&#40;bool, false&#41;&#10; l4_ilb_subsetting &#61; optional&#40;bool, false&#41;&#10; pod_security_policy &#61; optional&#40;bool, false&#41;&#10; resource_usage_export &#61; optional&#40;object&#40;&#123;&#10; dataset &#61; optional&#40;string&#41;&#10; enable_network_egress_metering &#61; optional&#40;bool, false&#41;&#10; enable_resource_consumption_metering &#61; optional&#40;bool, false&#41;&#10; &#125;&#41;&#41;&#10; shielded_nodes &#61; optional&#40;bool, false&#41;&#10; tpu &#61; optional&#40;bool, false&#41;&#10; upgrade_notifications &#61; optional&#40;object&#40;&#123;&#10; topic_id &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; vertical_pod_autoscaling &#61; optional&#40;bool, false&#41;&#10; workload_identity &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; workload_identity &#61; true&#10; resource_usage_export &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [issue_client_certificate](variables.tf#L106) | Enable issuing client certificate. | <code>bool</code> | | <code>false</code> |
| [labels](variables.tf#L112) | Cluster resource labels. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [logging_config](variables.tf#L123) | Logging configuration. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;SYSTEM_COMPONENTS&#34;&#93;</code> |
| [maintenance_config](variables.tf#L129) | Maintenance window configuration. | <code title="object&#40;&#123;&#10; daily_window_start_time &#61; optional&#40;string&#41;&#10; recurring_window &#61; optional&#40;object&#40;&#123;&#10; start_time &#61; string&#10; end_time &#61; string&#10; recurrence &#61; string&#10; &#125;&#41;&#41;&#10; maintenance_exclusions &#61; optional&#40;list&#40;object&#40;&#123;&#10; name &#61; string&#10; start_time &#61; string&#10; end_time &#61; string&#10; scope &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; daily_window_start_time &#61; &#34;03:00&#34;&#10; recurring_window &#61; null&#10; maintenance_exclusion &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [max_pods_per_node](variables.tf#L152) | Maximum number of pods per node in this cluster. | <code>number</code> | | <code>110</code> |
| [min_master_version](variables.tf#L158) | Minimum version of the master, defaults to the version of the most recent official release. | <code>string</code> | | <code>null</code> |
| [monitoring_config](variables.tf#L164) | Monitoring components. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;SYSTEM_COMPONENTS&#34;&#93;</code> |
| [node_locations](variables.tf#L175) | Zones in which the cluster's nodes are located. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [private_cluster_config](variables.tf#L182) | Private cluster configuration. | <code title="object&#40;&#123;&#10; enable_private_endpoint &#61; optional&#40;bool&#41;&#10; master_ipv4_cidr_block &#61; optional&#40;string&#41;&#10; master_global_access &#61; optional&#40;bool&#41;&#10; peering_config &#61; optional&#40;object&#40;&#123;&#10; export_routes &#61; optional&#40;bool&#41;&#10; import_routes &#61; optional&#40;bool&#41;&#10; project_id &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [release_channel](variables.tf#L202) | Release channel for GKE upgrades. | <code>string</code> | | <code>null</code> |
## Outputs

View File

@ -14,159 +14,216 @@
* limitations under the License.
*/
locals {
# The Google provider is unable to validate certain configurations of
# private_cluster_config when enable_private_nodes is false (provider docs)
is_private = try(var.private_cluster_config.enable_private_nodes, false)
peering = try(
google_container_cluster.cluster.private_cluster_config.0.peering_name,
null
)
peering_project_id = (
try(var.peering_config.project_id, null) == null
? var.project_id
: var.peering_config.project_id
)
}
resource "google_container_cluster" "cluster" {
provider = google-beta
project = var.project_id
name = var.name
description = var.description
location = var.location
node_locations = length(var.node_locations) == 0 ? null : var.node_locations
min_master_version = var.min_master_version
network = var.network
subnetwork = var.subnetwork
logging_service = var.monitoring_config != null ? null : var.logging_config == null ? var.logging_service : null
monitoring_service = var.monitoring_config == null ? var.monitoring_service : null
resource_labels = var.labels
default_max_pods_per_node = var.enable_autopilot ? null : var.default_max_pods_per_node
enable_intranode_visibility = var.enable_intranode_visibility
enable_l4_ilb_subsetting = var.enable_l4_ilb_subsetting
enable_shielded_nodes = var.enable_shielded_nodes
enable_tpu = var.enable_tpu
initial_node_count = 1
remove_default_node_pool = var.enable_autopilot ? null : true
datapath_provider = var.enable_dataplane_v2 ? "ADVANCED_DATAPATH" : "DATAPATH_PROVIDER_UNSPECIFIED"
enable_autopilot = var.enable_autopilot == true ? true : null
provider = google-beta
project = var.project_id
name = var.name
description = var.description
location = var.location
node_locations = (
length(var.node_locations) == 0 ? null : var.node_locations
)
min_master_version = var.min_master_version
network = var.vpc_config.network
subnetwork = var.vpc_config.subnetwork
resource_labels = var.labels
default_max_pods_per_node = (
var.enable_features.autopilot ? null : var.max_pods_per_node
)
enable_intranode_visibility = (
var.enable_features.autopilot ? null : var.enable_features.intranode_visibility
)
enable_l4_ilb_subsetting = var.enable_features.l4_ilb_subsetting
enable_shielded_nodes = (
var.enable_features.autopilot ? null : var.enable_features.shielded_nodes
)
enable_tpu = var.enable_features.tpu
initial_node_count = 1
remove_default_node_pool = var.enable_features.autopilot ? null : true
datapath_provider = (
var.enable_features.dataplane_v2
? "ADVANCED_DATAPATH"
: "DATAPATH_PROVIDER_UNSPECIFIED"
)
enable_autopilot = var.enable_features.autopilot ? true : null
# the default nodepool is deleted here, use the gke-nodepool module instead
# node_config {}
# NOTE: Default node_pool is deleted, so node_config (here) is extranneous.
# Specify that node_config as an parameter to gke-nodepool module instead.
# TODO(ludomagno): compute addons map in locals and use a single dynamic block
addons_config {
dynamic "dns_cache_config" {
# Pass the user-provided value when autopilot is disabled. When
# autopilot is enabled, pass the value only when the addon is
# set to true. This will fail but warns the user that autopilot
# doesn't support this option, instead of silently discarding
# and hiding the error
for_each = !var.enable_autopilot || (var.enable_autopilot && var.addons.dns_cache_config) ? [""] : []
for_each = !var.enable_features.autopilot ? [""] : []
content {
enabled = var.addons.dns_cache_config
enabled = var.enable_addons.dns_cache
}
}
http_load_balancing {
disabled = !var.addons.http_load_balancing
disabled = !var.enable_addons.http_load_balancing
}
horizontal_pod_autoscaling {
disabled = !var.addons.horizontal_pod_autoscaling
disabled = !var.enable_addons.horizontal_pod_autoscaling
}
dynamic "network_policy_config" {
for_each = !var.enable_autopilot ? [""] : []
for_each = !var.enable_features.autopilot ? [""] : []
content {
disabled = !var.addons.network_policy_config
disabled = !var.enable_addons.network_policy
}
}
cloudrun_config {
disabled = !var.addons.cloudrun_config
disabled = !var.enable_addons.cloudrun
}
istio_config {
disabled = !var.addons.istio_config.enabled
auth = var.addons.istio_config.tls ? "AUTH_MUTUAL_TLS" : "AUTH_NONE"
disabled = var.enable_addons.istio == null
auth = (
try(var.enable_addons.istio.enable_tls, false) ? "AUTH_MUTUAL_TLS" : "AUTH_NONE"
)
}
gce_persistent_disk_csi_driver_config {
enabled = var.enable_autopilot || var.addons.gce_persistent_disk_csi_driver_config
enabled = var.enable_addons.gce_persistent_disk_csi_driver
}
dynamic "gcp_filestore_csi_driver_config" {
# Pass the user-provided value when autopilot is disabled. When
# autopilot is enabled, pass the value only when the addon is
# set to true. This will fail but warns the user that autopilot
# doesn't support this option, instead of silently discarding
# and hiding the error
for_each = var.enable_autopilot && !var.addons.gcp_filestore_csi_driver_config ? [] : [""]
for_each = !var.enable_features.autopilot ? [""] : []
content {
enabled = var.addons.gcp_filestore_csi_driver_config
enabled = var.enable_addons.gcp_filestore_csi_driver
}
}
kalm_config {
enabled = var.addons.kalm_config
enabled = var.enable_addons.kalm
}
config_connector_config {
enabled = var.addons.config_connector_config
enabled = var.enable_addons.config_connector
}
gke_backup_agent_config {
enabled = var.addons.gke_backup_agent_config
enabled = var.enable_addons.gke_backup_agent
}
}
# TODO(ludomagno): support setting address ranges instead of range names
# https://www.terraform.io/docs/providers/google/r/container_cluster.html#cluster_ipv4_cidr_block
ip_allocation_policy {
cluster_secondary_range_name = var.secondary_range_pods
services_secondary_range_name = var.secondary_range_services
dynamic "authenticator_groups_config" {
for_each = var.enable_features.groups_for_rbac != null ? [""] : []
content {
security_group = var.enable_features.groups_for_rbac
}
}
dynamic "binary_authorization" {
for_each = var.enable_features.binary_authorization ? [""] : []
content {
evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE"
}
}
dynamic "cluster_autoscaling" {
for_each = var.cluster_autoscaling == null ? [] : [""]
content {
enabled = true
dynamic "resource_limits" {
for_each = var.cluster_autoscaling.cpu_limits != null ? [""] : []
content {
resource_type = "cpu"
minimum = var.cluster_autoscaling.cpu_limits.min
maximum = var.cluster_autoscaling.cpu_limits.max
}
}
dynamic "resource_limits" {
for_each = var.cluster_autoscaling.mem_limits != null ? [""] : []
content {
resource_type = "cpu"
minimum = var.cluster_autoscaling.mem_limits.min
maximum = var.cluster_autoscaling.mem_limits.max
}
}
// TODO: support GPUs too
}
}
dynamic "database_encryption" {
for_each = var.enable_features.database_encryption != null ? [""] : []
content {
state = var.enable_features.database_encryption.state
key_name = var.enable_features.database_encryption.key_name
}
}
dynamic "dns_config" {
for_each = var.enable_features.cloud_dns != null ? [""] : []
content {
cluster_dns = enable_features.cloud_dns.cluster_dns
cluster_dns_scope = enable_features.cloud_dns.cluster_dns_scope
cluster_dns_domain = enable_features.cloud_dns.cluster_dns_domain
}
}
dynamic "ip_allocation_policy" {
for_each = var.vpc_config.secondary_range_blocks != null ? [""] : []
content {
cluster_ipv4_cidr_block = var.vpc_config.secondary_range_blocks.pods
services_ipv4_cidr_block = var.vpc_config.secondary_range_blocks.services
}
}
dynamic "ip_allocation_policy" {
for_each = var.vpc_config.secondary_range_names != null ? [""] : []
content {
cluster_secondary_range_name = var.vpc_config.secondary_range_names.pods
services_secondary_range_name = var.vpc_config.secondary_range_names.services
}
}
dynamic "logging_config" {
for_each = var.logging_config != null ? [""] : []
content {
enable_components = var.logging_config
}
}
# https://www.terraform.io/docs/providers/google/r/container_cluster.html#daily_maintenance_window
maintenance_policy {
dynamic "daily_maintenance_window" {
for_each = var.maintenance_config != null && lookup(var.maintenance_config, "daily_maintenance_window", null) != null ? [var.maintenance_config.daily_maintenance_window] : []
iterator = config
for_each = (
try(var.maintenance_config.daily_window_start_time, null) != null
? [""]
: []
)
content {
start_time = config.value.start_time
start_time = var.maintenance_config.daily_window_start_time
}
}
dynamic "recurring_window" {
for_each = var.maintenance_config != null && lookup(var.maintenance_config, "recurring_window", null) != null ? [var.maintenance_config.recurring_window] : []
iterator = config
for_each = (
try(var.maintenance_config.recurring_window, null) != null
? [""]
: []
)
content {
start_time = config.value.start_time
end_time = config.value.end_time
recurrence = config.value.recurrence
start_time = var.maintenance_config.recurring_window.start_time
end_time = var.maintenance_config.recurring_window.end_time
recurrence = var.maintenance_config.recurring_window.recurrence
}
}
dynamic "maintenance_exclusion" {
for_each = var.maintenance_config != null && lookup(var.maintenance_config, "maintenance_exclusion", null) != null ? var.maintenance_config.maintenance_exclusion : []
iterator = config
for_each = (
try(var.maintenance_config.maintenance_exclusions, null) == null
? []
: var.maintenance_config.maintenance_exclusions
)
iterator = exclusion
content {
exclusion_name = config.value.exclusion_name
start_time = config.value.start_time
end_time = config.value.end_time
exclusion_name = exclusion.value.name
start_time = exclusion.value.start_time
end_time = exclusion.value.end_time
}
}
}
master_auth {
client_certificate_config {
issue_client_certificate = false
issue_client_certificate = var.issue_client_certificate
}
}
dynamic "master_authorized_networks_config" {
for_each = (
length(var.master_authorized_ranges) == 0
? []
: [var.master_authorized_ranges]
)
iterator = ranges
for_each = var.vpc_config.master_authorized_ranges != null ? [""] : []
content {
dynamic "cidr_blocks" {
for_each = ranges.value
for_each = var.vpc_config.master_authorized_ranges
iterator = range
content {
cidr_block = range.value
@ -176,69 +233,58 @@ resource "google_container_cluster" "cluster" {
}
}
#the network_policy block is enabled if network_policy_config and network_dataplane_v2 is set to false. Dataplane V2 has built-in network policies.
dynamic "network_policy" {
for_each = var.addons.network_policy_config ? [""] : []
dynamic "monitoring_config" {
for_each = var.monitoring_config != null ? [""] : []
content {
enabled = var.enable_dataplane_v2 ? false : true
provider = var.enable_dataplane_v2 ? "PROVIDER_UNSPECIFIED" : "CALICO"
enable_components = var.monitoring_config
}
}
# dataplane v2 has bult-in network policies
dynamic "network_policy" {
for_each = (
var.enable_addons.network_policy && !var.enable_features.dataplane_v2
? [""]
: []
)
content {
enabled = true
provider = "CALICO"
}
}
dynamic "notification_config" {
for_each = var.enable_features.upgrade_notifications != null ? [""] : []
content {
pubsub {
enabled = true
topic = (
try(var.enable_features.upgrade_notifications.topic_id, null) != null
? var.enable_features.upgrade_notifications.topic_id
: google_pubsub_topic.notifications[0].id
)
}
}
}
dynamic "private_cluster_config" {
for_each = local.is_private ? [var.private_cluster_config] : []
iterator = config
for_each = (
var.private_cluster_config != null ? [""] : []
)
content {
enable_private_nodes = config.value.enable_private_nodes
enable_private_endpoint = config.value.enable_private_endpoint
master_ipv4_cidr_block = config.value.master_ipv4_cidr_block
enable_private_nodes = true
enable_private_endpoint = var.private_cluster_config.enable_private_endpoint
master_ipv4_cidr_block = var.private_cluster_config.master_ipv4_cidr_block
master_global_access_config {
enabled = config.value.master_global_access
enabled = var.private_cluster_config.master_global_access
}
}
}
# beta features
dynamic "authenticator_groups_config" {
for_each = var.authenticator_security_group == null ? [] : [""]
content {
security_group = var.authenticator_security_group
}
}
dynamic "cluster_autoscaling" {
for_each = var.cluster_autoscaling.enabled ? [var.cluster_autoscaling] : []
iterator = config
content {
enabled = true
resource_limits {
resource_type = "cpu"
minimum = config.value.cpu_min
maximum = config.value.cpu_max
}
resource_limits {
resource_type = "memory"
minimum = config.value.memory_min
maximum = config.value.memory_max
}
// TODO: support GPUs too
}
}
dynamic "database_encryption" {
for_each = var.database_encryption.enabled ? [var.database_encryption] : []
iterator = config
content {
state = config.value.state
key_name = config.value.key_name
}
}
dynamic "pod_security_policy_config" {
for_each = var.pod_security_policy != null ? [""] : []
for_each = var.enable_features.pod_security_policy ? [""] : []
content {
enabled = var.pod_security_policy
enabled = var.enable_features.pod_security_policy
}
}
@ -251,86 +297,61 @@ resource "google_container_cluster" "cluster" {
dynamic "resource_usage_export_config" {
for_each = (
var.resource_usage_export_config.enabled != null
&&
var.resource_usage_export_config.dataset != null
? [""] : []
try(var.enable_features.resource_usage_export.dataset, null) != null
? [""]
: []
)
content {
enable_network_egress_metering = var.resource_usage_export_config.enabled
enable_network_egress_metering = (
var.enable_features.resource_usage_export.enable_network_egress_metering
)
enable_resource_consumption_metering = (
var.enable_features.resource_usage_export.enable_resource_consumption_metering
)
bigquery_destination {
dataset_id = var.resource_usage_export_config.dataset
dataset_id = var.enable_features.resource_usage_export.dataset
}
}
}
dynamic "vertical_pod_autoscaling" {
for_each = var.vertical_pod_autoscaling == null ? [] : [""]
for_each = var.enable_features.vertical_pod_autoscaling ? [""] : []
content {
enabled = var.vertical_pod_autoscaling
enabled = var.enable_features.vertical_pod_autoscaling
}
}
dynamic "workload_identity_config" {
for_each = var.workload_identity && !var.enable_autopilot ? [""] : []
for_each = var.enable_features.workload_identity ? [""] : []
content {
workload_pool = "${var.project_id}.svc.id.goog"
}
}
dynamic "monitoring_config" {
for_each = var.monitoring_config != null ? [""] : []
content {
enable_components = var.monitoring_config
}
}
dynamic "logging_config" {
for_each = var.logging_config != null ? [""] : []
content {
enable_components = var.logging_config
}
}
dynamic "binary_authorization" {
for_each = var.enable_binary_authorization ? [""] : []
content {
evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE"
}
}
dynamic "dns_config" {
for_each = var.dns_config != null ? [""] : []
content {
cluster_dns = var.dns_config.cluster_dns
cluster_dns_scope = var.dns_config.cluster_dns_scope
cluster_dns_domain = var.dns_config.cluster_dns_domain
}
}
dynamic "notification_config" {
for_each = var.notification_config ? [""] : []
content {
pubsub {
enabled = var.notification_config
topic = var.notification_config ? google_pubsub_topic.notifications[0].id : null
}
}
}
}
resource "google_compute_network_peering_routes_config" "gke_master" {
count = local.is_private && var.peering_config != null ? 1 : 0
project = local.peering_project_id
peering = local.peering
network = element(reverse(split("/", var.network)), 0)
import_custom_routes = var.peering_config.import_routes
export_custom_routes = var.peering_config.export_routes
count = (
try(var.private_cluster_config.peering_config, null) != null ? 1 : 0
)
project = (
try(var.private_cluster_config.peering_config, null) == null
? var.project_id
: var.private_cluster_config.peering_config.project_id
)
peering = try(
google_container_cluster.cluster.private_cluster_config.0.peering_name,
null
)
network = element(reverse(split("/", var.vpc_config.network)), 0)
import_custom_routes = var.private_cluster_config.peering_config.import_routes
export_custom_routes = var.private_cluster_config.peering_config.export_routes
}
resource "google_pubsub_topic" "notifications" {
count = var.notification_config ? 1 : 0
name = "gke-pubsub-notifications"
count = (
try(var.enable_features.upgrade_notifications.topic_id, null) == null ? 0 : 1
)
name = "gke-pubsub-notifications"
labels = {
content = "gke-notifications"
}

View File

@ -53,7 +53,7 @@ output "name" {
output "notifications" {
description = "GKE PubSub notifications topic."
value = var.notification_config ? google_pubsub_topic.notifications[0].id : null
value = try(google_pubsub_topic.notifications[0].id, null)
}
output "self_link" {

View File

@ -14,84 +14,25 @@
* limitations under the License.
*/
variable "addons" {
description = "Addons enabled in the cluster (true means enabled)."
type = object({
cloudrun_config = bool
dns_cache_config = bool
horizontal_pod_autoscaling = bool
http_load_balancing = bool
istio_config = object({
enabled = bool
tls = bool
})
network_policy_config = bool
gce_persistent_disk_csi_driver_config = bool
gcp_filestore_csi_driver_config = bool
config_connector_config = bool
kalm_config = bool
gke_backup_agent_config = bool
})
default = {
cloudrun_config = false
dns_cache_config = false
horizontal_pod_autoscaling = true
http_load_balancing = true
istio_config = {
enabled = false
tls = false
}
network_policy_config = false
gce_persistent_disk_csi_driver_config = false
gcp_filestore_csi_driver_config = false
config_connector_config = false
kalm_config = false
gke_backup_agent_config = false
}
}
variable "authenticator_security_group" {
description = "RBAC security group for Google Groups for GKE, format is gke-security-groups@yourdomain.com."
type = string
default = null
}
variable "cluster_autoscaling" {
description = "Enable and configure limits for Node Auto-Provisioning with Cluster Autoscaler."
type = object({
enabled = bool
cpu_min = number
cpu_max = number
memory_min = number
memory_max = number
auto_provisioning_defaults = optional(object({
boot_disk_kms_key = optional(string)
image_type = optional(string)
oauth_scopes = optional(list(string))
service_account = optional(string)
}))
cpu_limits = optional(object({
min = number
max = number
}))
mem_limits = optional(object({
min = number
max = number
}))
})
default = {
enabled = false
cpu_min = 0
cpu_max = 0
memory_min = 0
memory_max = 0
}
}
variable "database_encryption" {
description = "Enable and configure GKE application-layer secrets encryption."
type = object({
enabled = bool
state = string
key_name = string
})
default = {
enabled = false
state = "DECRYPTED"
key_name = null
}
}
variable "default_max_pods_per_node" {
description = "Maximum number of pods per node in this cluster."
type = number
default = 110
default = null
}
variable "description" {
@ -100,58 +41,74 @@ variable "description" {
default = null
}
variable "dns_config" {
description = "Configuration for Using Cloud DNS for GKE."
variable "enable_addons" {
description = "Addons enabled in the cluster (true means enabled)."
type = object({
cluster_dns = string
cluster_dns_scope = string
cluster_dns_domain = string
cloudrun = optional(bool, false)
config_connector = optional(bool, false)
dns_cache = optional(bool, false)
gce_persistent_disk_csi_driver = optional(bool, false)
gcp_filestore_csi_driver = optional(bool, false)
gke_backup_agent = optional(bool, false)
horizontal_pod_autoscaling = optional(bool, false)
http_load_balancing = optional(bool, false)
istio = optional(object({
enable_tls = bool
}))
kalm = optional(bool, false)
network_policy = optional(bool, false)
})
default = null
default = {
horizontal_pod_autoscaling = true
http_load_balancing = true
}
nullable = false
}
variable "enable_autopilot" {
description = "Create cluster in autopilot mode. With autopilot there's no need to create node-pools and some features are not supported (e.g. setting default_max_pods_per_node)."
variable "enable_features" {
description = "Enable cluster-level features. Certain features allow configuration."
type = object({
autopilot = optional(bool, false)
binary_authorization = optional(bool, false)
cloud_dns = optional(object({
provider = optional(string)
scope = optional(string)
domain = optional(string)
}))
database_encryption = optional(object({
state = string
key_name = string
}))
dataplane_v2 = optional(bool, false)
groups_for_rbac = optional(string)
intranode_visibility = optional(bool, false)
l4_ilb_subsetting = optional(bool, false)
pod_security_policy = optional(bool, false)
resource_usage_export = optional(object({
dataset = optional(string)
enable_network_egress_metering = optional(bool, false)
enable_resource_consumption_metering = optional(bool, false)
}))
shielded_nodes = optional(bool, false)
tpu = optional(bool, false)
upgrade_notifications = optional(object({
topic_id = optional(string)
}))
vertical_pod_autoscaling = optional(bool, false)
workload_identity = optional(bool, false)
})
default = {
workload_identity = true
resource_usage_export = null
}
}
variable "issue_client_certificate" {
description = "Enable issuing client certificate."
type = bool
default = false
}
variable "enable_binary_authorization" {
description = "Enable Google Binary Authorization."
type = bool
default = false
}
variable "enable_dataplane_v2" {
description = "Enable Dataplane V2 on the cluster, will disable network_policy addons config."
type = bool
default = false
}
variable "enable_intranode_visibility" {
description = "Enable intra-node visibility to make same node pod to pod traffic visible."
type = bool
default = null
}
variable "enable_l4_ilb_subsetting" {
description = "Enable L4ILB Subsetting."
type = bool
default = null
}
variable "enable_shielded_nodes" {
description = "Enable Shielded Nodes features on all nodes in this cluster."
type = bool
default = null
}
variable "enable_tpu" {
description = "Enable Cloud TPU resources in this cluster."
type = bool
default = null
}
variable "labels" {
description = "Cluster resource labels."
type = map(string)
@ -164,47 +121,38 @@ variable "location" {
}
variable "logging_config" {
description = "Logging configuration (enabled components)."
description = "Logging configuration."
type = list(string)
default = null
}
variable "logging_service" {
description = "Logging service (disable with an empty string)."
type = string
default = "logging.googleapis.com/kubernetes"
default = ["SYSTEM_COMPONENTS"]
}
variable "maintenance_config" {
description = "Maintenance window configuration."
type = object({
daily_maintenance_window = object({
start_time = string
})
recurring_window = object({
daily_window_start_time = optional(string)
recurring_window = optional(object({
start_time = string
end_time = string
recurrence = string
})
maintenance_exclusion = list(object({
exclusion_name = string
start_time = string
end_time = string
}))
maintenance_exclusions = optional(list(object({
name = string
start_time = string
end_time = string
scope = optional(string)
})))
})
default = {
daily_maintenance_window = {
start_time = "03:00"
}
recurring_window = null
maintenance_exclusion = []
daily_window_start_time = "03:00"
recurring_window = null
maintenance_exclusion = []
}
}
variable "master_authorized_ranges" {
description = "External Ip address ranges that can access the Kubernetes cluster master through HTTPS."
type = map(string)
default = {}
variable "max_pods_per_node" {
description = "Maximum number of pods per node in this cluster."
type = number
default = 110
}
variable "min_master_version" {
@ -214,15 +162,9 @@ variable "min_master_version" {
}
variable "monitoring_config" {
description = "Monitoring configuration (enabled components)."
description = "Monitoring components."
type = list(string)
default = null
}
variable "monitoring_service" {
description = "Monitoring service (disable with an empty string)."
type = string
default = "monitoring.googleapis.com/kubernetes"
default = ["SYSTEM_COMPONENTS"]
}
variable "name" {
@ -230,46 +172,24 @@ variable "name" {
type = string
}
variable "network" {
description = "Name or self link of the VPC used for the cluster. Use the self link for Shared VPC."
type = string
}
variable "node_locations" {
description = "Zones in which the cluster's nodes are located."
type = list(string)
default = []
}
variable "notification_config" {
description = "GKE Cluster upgrade notifications via PubSub."
type = bool
default = false
}
variable "peering_config" {
description = "Configure peering with the master VPC for private clusters."
type = object({
export_routes = bool
import_routes = bool
project_id = string
})
default = null
}
variable "pod_security_policy" {
description = "Enable the PodSecurityPolicy feature."
type = bool
default = null
nullable = false
}
variable "private_cluster_config" {
description = "Enable and configure private cluster, private nodes must be true if used."
description = "Private cluster configuration."
type = object({
enable_private_nodes = bool
enable_private_endpoint = bool
master_ipv4_cidr_block = string
master_global_access = bool
enable_private_endpoint = optional(bool)
master_ipv4_cidr_block = optional(string)
master_global_access = optional(bool)
peering_config = optional(object({
export_routes = optional(bool)
import_routes = optional(bool)
project_id = optional(string)
}))
})
default = null
}
@ -285,41 +205,20 @@ variable "release_channel" {
default = null
}
variable "resource_usage_export_config" {
description = "Configure the ResourceUsageExportConfig feature."
variable "vpc_config" {
description = "VPC-level configuration."
type = object({
enabled = bool
dataset = string
network = string
subnetwork = string
secondary_range_blocks = optional(object({
pods = string
services = string
}), )
secondary_range_names = optional(object({
pods = string
services = string
}), { pods = "pods", services = "services" })
master_authorized_ranges = optional(map(string))
})
default = {
enabled = null
dataset = null
}
}
variable "secondary_range_pods" {
description = "Subnet secondary range name used for pods."
type = string
}
variable "secondary_range_services" {
description = "Subnet secondary range name used for services."
type = string
}
variable "subnetwork" {
description = "VPC subnetwork name or self link."
type = string
}
variable "vertical_pod_autoscaling" {
description = "Enable the Vertical Pod Autoscaling feature."
type = bool
default = null
}
variable "workload_identity" {
description = "Enable the Workload Identity feature."
type = bool
default = true
nullable = false
}

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -48,18 +48,20 @@ module "vpc" {
}
module "cluster_1" {
source = "./fabric/modules/gke-cluster"
project_id = module.project.project_id
name = "cluster-1"
location = "europe-west1-b"
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["europe-west1/cluster-1"]
secondary_range_pods = "pods"
secondary_range_services = "services"
enable_dataplane_v2 = true
master_authorized_ranges = { rfc1918_10_8 = "10.0.0.0/8" }
source = "./fabric/modules/gke-cluster"
project_id = module.project.project_id
name = "cluster-1"
location = "europe-west1"
vpc_config = {
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["europe-west1/cluster-1"]
master_authorized_ranges = { rfc1918_10_8 = "10.0.0.0/8" }
}
enable_features = {
dataplane_v2 = true
workload_identity = true
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = true
master_ipv4_cidr_block = "192.168.0.0/28"
master_global_access = false
@ -225,27 +227,24 @@ module "firewall" {
}
module "cluster_1" {
source = "./fabric/modules/gke-cluster"
project_id = module.project.project_id
name = "cluster-1"
location = "europe-wes1"
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["europe-west1/subnet-cluster-1"]
secondary_range_pods = "pods"
secondary_range_services = "services"
source = "./fabric/modules/gke-cluster"
project_id = module.project.project_id
name = "cluster-1"
location = "europe-west1"
vpc_config = {
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["europe-west1/subnet-cluster-1"]
master_authorized_ranges = {
mgmt = "10.0.0.0/28"
pods-cluster-1 = "10.3.0.0/16"
}
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "192.168.1.0/28"
master_global_access = true
}
master_authorized_ranges = {
mgmt = "10.0.0.0/28"
pods-cluster-1 = "10.3.0.0/16"
}
enable_autopilot = false
release_channel = "REGULAR"
workload_identity = true
release_channel = "REGULAR"
labels = {
mesh_id = "proj-${module.project.number}"
}
@ -266,25 +265,22 @@ module "cluster_1_nodepool" {
module "cluster_2" {
source = "./fabric/modules/gke-cluster"
project_id = module.project.project_id
name = "cluster-1"
location = "europe-wes1"
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["europe-west4/subnet-cluster-2"]
secondary_range_pods = "pods"
secondary_range_services = "services"
name = "cluster-2"
location = "europe-west4"
vpc_config = {
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["europe-west4/subnet-cluster-2"]
master_authorized_ranges = {
mgmt = "10.0.0.0/28"
pods-cluster-1 = "10.3.0.0/16"
}
}
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "192.168.2.0/28"
master_global_access = true
}
master_authorized_ranges = {
mgmt = "10.0.0.0/28"
pods-cluster-1 = "10.1.0.0/16"
}
enable_autopilot = false
release_channel = "REGULAR"
workload_identity = true
release_channel = "REGULAR"
labels = {
mesh_id = "proj-${module.project.number}"
}

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

View File

@ -13,7 +13,7 @@
# limitations under the License.
terraform {
required_version = ">= 1.3.0"
required_version = ">= 1.3.2"
required_providers {
google = {
source = "hashicorp/google"

Some files were not shown because too many files have changed in this diff Show More