# Google Cloud Platform Infrastructure Module # Creates GKE cluster, networking, and supporting resources for GCP environments locals { env = var.environment_config # Extract GCP-specific config gcp_config = try(local.env.gcp, {}) # Extract infrastructure config infra = try(local.env.infrastructure, {}) k8s_config = try(local.infra.kubernetes, {}) net_config = try(local.infra.networking, {}) # Naming name_prefix = "${local.env.name}-${var.environment}" # Node pools node_pools = try(local.k8s_config.node_pools, {}) # Project and region project_id = try(local.gcp_config.project_id, var.gcp_project_id) region = try(local.env.region, var.gcp_default_region) } # VPC Network resource "google_compute_network" "main" { name = "${local.name_prefix}-vpc" auto_create_subnetworks = false project = local.project_id tags = var.tags } # Subnets resource "google_compute_subnetwork" "gke" { for_each = { for idx, subnet in try(local.net_config.subnets, []) : subnet.name => subnet if subnet.name == "gke" || subnet.name == "eks" || subnet.name == "aks" } name = "${local.name_prefix}-subnet-${each.key}" ip_cidr_range = each.value.cidr region = try(each.value.region, local.region) network = google_compute_network.main.id project = local.project_id private_ip_google_access = true secondary_ip_range { range_name = "${local.name_prefix}-pods" ip_cidr_range = cidrsubnet(each.value.cidr, 8, 1) } secondary_ip_range { range_name = "${local.name_prefix}-services" ip_cidr_range = cidrsubnet(each.value.cidr, 8, 2) } } resource "google_compute_subnetwork" "validators" { for_each = { for idx, subnet in try(local.net_config.subnets, []) : subnet.name => subnet if subnet.name == "validators" } name = "${local.name_prefix}-subnet-validators" ip_cidr_range = each.value.cidr region = try(each.value.region, local.region) network = google_compute_network.main.id project = local.project_id private_ip_google_access = true } resource "google_compute_subnetwork" "rpc" { for_each = { for idx, subnet in try(local.net_config.subnets, []) : subnet.name => subnet if subnet.name == "rpc" } name = "${local.name_prefix}-subnet-rpc" ip_cidr_range = each.value.cidr region = try(each.value.region, local.region) network = google_compute_network.main.id project = local.project_id private_ip_google_access = true } # Firewall Rules resource "google_compute_firewall" "allow_internal" { name = "${local.name_prefix}-allow-internal" network = google_compute_network.main.name project = local.project_id allow { protocol = "icmp" } allow { protocol = "tcp" ports = ["0-65535"] } allow { protocol = "udp" ports = ["0-65535"] } source_ranges = [google_compute_network.main.ipv4_range] tags = var.tags } resource "google_compute_firewall" "allow_validators_p2p" { name = "${local.name_prefix}-allow-validators-p2p" network = google_compute_network.main.name project = local.project_id allow { protocol = "tcp" ports = ["30303"] } source_ranges = [google_compute_network.main.ipv4_range] target_tags = ["validators"] tags = var.tags } resource "google_compute_firewall" "allow_rpc" { name = "${local.name_prefix}-allow-rpc" network = google_compute_network.main.name project = local.project_id allow { protocol = "tcp" ports = ["8545", "8546"] } source_ranges = ["0.0.0.0/0"] target_tags = ["rpc"] tags = var.tags } # GKE Cluster resource "google_container_cluster" "main" { name = "${local.name_prefix}-gke" location = local.region project = local.project_id # We can't create a cluster with no node pool defined, but we want to only use # separately managed node pools. So we create the smallest possible default # node pool and immediately delete it. remove_default_node_pool = true initial_node_count = 1 network = google_compute_network.main.name subnetwork = [for s in google_compute_subnetwork.gke : s.name][0] # Enable Workload Identity workload_identity_config { workload_pool = "${local.project_id}.svc.id.goog" } # Enable private cluster private_cluster_config { enable_private_nodes = true enable_private_endpoint = false master_ipv4_cidr_block = "172.16.0.0/28" } # Enable logging and monitoring logging_service = "logging.googleapis.com/kubernetes" monitoring_service = "monitoring.googleapis.com/kubernetes" # Network policy network_policy { enabled = true } # Release channel release_channel { channel = "REGULAR" } # Maintenance window maintenance_policy { daily_maintenance_window { start_time = "03:00" } } depends_on = [ google_project_service.container, google_project_service.compute, ] tags = var.tags } # Delete default node pool resource "google_container_node_pool" "default" { name = "${local.name_prefix}-default-pool" location = local.region cluster = google_container_cluster.main.name project = local.project_id node_count = 0 # Immediately scale to 0 to effectively delete it management { auto_repair = true auto_upgrade = true } } # Node Pools resource "google_container_node_pool" "system" { count = try(local.node_pools.system.count, 0) > 0 ? 1 : 0 name = "system" location = local.region cluster = google_container_cluster.main.name project = local.project_id node_count = try(local.node_pools.system.count, 1) node_config { machine_type = try(local.node_pools.system.machine_type, "e2-medium") disk_size_gb = 100 disk_type = "pd-standard" service_account = google_service_account.gke_nodes.email oauth_scopes = [ "https://www.googleapis.com/auth/cloud-platform", ] labels = { pool = "system" role = "system" } tags = ["system"] } management { auto_repair = true auto_upgrade = true } autoscaling { min_node_count = 1 max_node_count = try(local.node_pools.system.count, 1) * 2 } } resource "google_container_node_pool" "validators" { count = try(local.node_pools.validators.count, 0) > 0 ? 1 : 0 name = "validators" location = local.region cluster = google_container_cluster.main.name project = local.project_id node_count = try(local.node_pools.validators.count, 1) node_config { machine_type = try(local.node_pools.validators.machine_type, "e2-medium") disk_size_gb = 512 disk_type = "pd-ssd" service_account = google_service_account.gke_nodes.email oauth_scopes = [ "https://www.googleapis.com/auth/cloud-platform", ] labels = { pool = "validators" role = "validator" } taint { key = "role" value = "validator" effect = "NO_SCHEDULE" } tags = ["validators"] } management { auto_repair = true auto_upgrade = true } autoscaling { min_node_count = 1 max_node_count = try(local.node_pools.validators.count, 1) * 2 } } resource "google_container_node_pool" "rpc" { count = try(local.node_pools.rpc.count, 0) > 0 ? 1 : 0 name = "rpc" location = local.region cluster = google_container_cluster.main.name project = local.project_id node_count = try(local.node_pools.rpc.count, 1) node_config { machine_type = try(local.node_pools.rpc.machine_type, "e2-medium") disk_size_gb = 256 disk_type = "pd-ssd" service_account = google_service_account.gke_nodes.email oauth_scopes = [ "https://www.googleapis.com/auth/cloud-platform", ] labels = { pool = "rpc" role = "rpc" } tags = ["rpc"] } management { auto_repair = true auto_upgrade = true } autoscaling { min_node_count = 1 max_node_count = try(local.node_pools.rpc.count, 1) * 2 } } # Service Account for GKE nodes resource "google_service_account" "gke_nodes" { account_id = "${local.name_prefix}-gke-nodes" display_name = "GKE Nodes Service Account" project = local.project_id } resource "google_project_iam_member" "gke_nodes" { project = local.project_id role = "roles/container.nodeServiceAccount" member = "serviceAccount:${google_service_account.gke_nodes.email}" } # Enable required APIs resource "google_project_service" "container" { project = local.project_id service = "container.googleapis.com" disable_on_destroy = false } resource "google_project_service" "compute" { project = local.project_id service = "compute.googleapis.com" disable_on_destroy = false }