# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ############################################################################### # Host and service projects # ############################################################################### # the container.hostServiceAgentUser role is needed for GKE on shared VPC # see: https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-shared-vpc#grant_host_service_agent_role module "project-host" { source = "../../../modules/project" parent = var.root_node billing_account = var.billing_account_id prefix = var.prefix name = "net" services = concat(var.project_services, ["dns.googleapis.com"]) shared_vpc_host_config = { enabled = true } iam = { "roles/owner" = var.owners_host } } module "project-svc-gce" { source = "../../../modules/project" parent = var.root_node billing_account = var.billing_account_id prefix = var.prefix name = "gce" services = var.project_services compute_metadata = { enable-oslogin = "true" } shared_vpc_service_config = { host_project = module.project-host.project_id service_identity_iam = { "roles/compute.networkUser" = ["cloudservices"] } } iam = { "roles/compute.osAdminLogin" = var.owners_gce "roles/owner" = var.owners_gce } } # the container.developer role assigned to the bastion instance service account # allows to fetch GKE credentials from bastion for clusters in this project module "project-svc-gke" { source = "../../../modules/project" parent = var.root_node billing_account = var.billing_account_id prefix = var.prefix name = "gke" services = var.project_services shared_vpc_service_config = { host_project = module.project-host.project_id service_identity_iam = { "roles/container.hostServiceAgentUser" = ["container-engine"] "roles/compute.networkUser" = ["container-engine"] } } iam = merge( { "roles/container.developer" = [module.vm-bastion.service_account_iam_email] "roles/owner" = var.owners_gke }, var.cluster_create ? { "roles/logging.logWriter" = [module.cluster-1-nodepool-1[0].service_account_iam_email] "roles/monitoring.metricWriter" = [module.cluster-1-nodepool-1[0].service_account_iam_email] } : {} ) } ################################################################################ # Networking # ################################################################################ # subnet IAM bindings control which identities can use the individual subnets module "vpc-shared" { source = "../../../modules/net-vpc" project_id = module.project-host.project_id name = "shared-vpc" subnets = [ { ip_cidr_range = var.ip_ranges.gce name = "gce" region = var.region iam = { "roles/compute.networkUser" = concat(var.owners_gce, [ "serviceAccount:${module.project-svc-gce.service_accounts.cloud_services}", ]) } }, { ip_cidr_range = var.ip_ranges.gke name = "gke" region = var.region secondary_ip_ranges = { pods = var.ip_secondary_ranges.gke-pods services = var.ip_secondary_ranges.gke-services } iam = { "roles/compute.networkUser" = concat(var.owners_gke, [ "serviceAccount:${module.project-svc-gke.service_accounts.cloud_services}", "serviceAccount:${module.project-svc-gke.service_accounts.robots.container-engine}", ]) "roles/compute.securityAdmin" = [ "serviceAccount:${module.project-svc-gke.service_accounts.robots.container-engine}", ] } } ] } module "vpc-shared-firewall" { source = "../../../modules/net-vpc-firewall" project_id = module.project-host.project_id network = module.vpc-shared.name default_rules_config = { admin_ranges = values(var.ip_ranges) } } module "nat" { source = "../../../modules/net-cloudnat" project_id = module.project-host.project_id region = var.region name = "vpc-shared" router_create = true router_network = module.vpc-shared.name } ################################################################################ # DNS # ################################################################################ module "host-dns" { source = "../../../modules/dns" project_id = module.project-host.project_id name = "example" zone_config = { domain = "example.com." private = { client_networks = [module.vpc-shared.self_link] } } recordsets = { "A localhost" = { records = ["127.0.0.1"] } "A bastion" = { records = [module.vm-bastion.internal_ip] } } } ################################################################################ # VM # ################################################################################ module "vm-bastion" { source = "../../../modules/compute-vm" project_id = module.project-svc-gce.project_id zone = "${var.region}-b" name = "bastion" network_interfaces = [{ network = module.vpc-shared.self_link subnetwork = lookup(module.vpc-shared.subnet_self_links, "${var.region}/gce", null) nat = false addresses = null }] tags = ["ssh"] metadata = { startup-script = join("\n", [ "#! /bin/bash", "apt-get update", "apt-get install -y bash-completion kubectl dnsutils tinyproxy", "grep -qxF 'Allow localhost' /etc/tinyproxy/tinyproxy.conf || echo 'Allow localhost' >> /etc/tinyproxy/tinyproxy.conf", "service tinyproxy restart" ]) } service_account = { auto_create = true } } ################################################################################ # GKE # ################################################################################ module "cluster-1" { source = "../../../modules/gke-cluster-standard" 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 } master_ipv4_cidr_block = var.private_service_ranges.cluster-1 } max_pods_per_node = 32 private_cluster_config = { enable_private_endpoint = true master_global_access = true } labels = { environment = "test" } deletion_protection = var.deletion_protection } module "cluster-1-nodepool-1" { source = "../../../modules/gke-nodepool" count = var.cluster_create ? 1 : 0 name = "nodepool-1" project_id = module.project-svc-gke.project_id location = module.cluster-1[0].location cluster_name = module.cluster-1[0].name cluster_id = module.cluster-1[0].id service_account = { create = true } }