# ── Vault LB — GCP Global HTTPS LB ─────────────────────────────────────────── # # LB frontend is unchanged: forwarding rule → target HTTPS proxy → url map → backend. # Backend uses GKE container-native NEGs (cut over from GCE instance groups). # # Architecture (GKE): # - Vault Helm chart runs 3 pods in namespace: vault on GKE neuron-platform cluster # - GKE auto-creates zonal container-native NEGs via Service annotation: # cloud.google.com/neg: '{"exposed_ports":{"8200":{}}}' # - NEG backends replace GCE instance group backends in the Global HTTPS LB # - DNS unchanged: vault.neuralplatform.ai → 34.54.164.21 (same GCP Global LB IP) # # GCE nodes (vault-node-1/2/3) and their instance groups have been removed. # GKE Vault (via Workload Identity + vault-unseal SA) is the sole Vault backend. locals { # Container-native NEG names created by GKE from the Vault Service annotation: # cloud.google.com/neg: '{"exposed_ports":{"8200":{}}}' # GKE creates one NEG per zone where Vault pods are scheduled. # Confirmed with: gcloud compute network-endpoint-groups list --project neuron-785695 vault_neg_names = { "us-central1-b" = "k8s1-bfbeff02-vault-vault-helm-gke-8200-db1a474f" "us-central1-c" = "k8s1-bfbeff02-vault-vault-helm-gke-8200-db1a474f" "us-central1-f" = "k8s1-bfbeff02-vault-vault-helm-gke-8200-db1a474f" } } # ── GKE container-native NEG data sources ──────────────────────────────────── # GKE auto-creates these when the Vault Service annotation is applied. data "google_compute_network_endpoint_group" "vault_gke" { for_each = local.vault_neg_names name = each.value zone = each.key project = var.project_id } # ── Firewall — GKE health checks ───────────────────────────────────────────── # Allow GCP health check probers to reach pod IPs on port 8200. # Container-native NEGs direct health checks to pod IPs (not node IPs). # GKE Autopilot pod CIDR: 10.45.128.0/22 (from cluster ip_allocation_policy). # Without this rule, GCP LB health checks fail → "no healthy upstream". # No target_tags — applies to all instances/pods in the default network. # Safe: GCP health check ranges (130.211.0.0/22, 35.191.0.0/16) are GCP-internal only. resource "google_compute_firewall" "vault_api_gke" { name = "vault-api-from-lb-gke" network = "default" project = var.project_id direction = "INGRESS" priority = 1000 allow { protocol = "tcp" ports = ["8200"] } # GCP health check source ranges only — restricted port, low risk source_ranges = ["130.211.0.0/22", "35.191.0.0/16"] } # ── Regional HTTPS LB for vault.neuralplatform.ai ───────────────────────────── # Global external HTTPS LB with a Google-managed cert for vault.neuralplatform.ai. # # TLS is terminated at the LB. Vault listens on plain 8200 internally. # Cloudflare DNS A record for vault.neuralplatform.ai → vault_lb_ip output below. resource "google_compute_global_address" "vault" { name = "vault-ip" project = var.project_id } resource "google_compute_managed_ssl_certificate" "vault" { name = "vault-cert" project = var.project_id managed { domains = ["vault.neuralplatform.ai"] } } resource "google_compute_health_check" "vault" { name = "vault-health" project = var.project_id # Vault listens on plain HTTP (tls_disable = true) — TLS is terminated at the LB http_health_check { port = 8200 request_path = "/v1/sys/health?standbyok=true&sealedok=true&uninitcode=200" } check_interval_sec = 15 timeout_sec = 5 healthy_threshold = 2 unhealthy_threshold = 3 } resource "google_compute_backend_service" "vault" { name = "vault-backend" project = var.project_id load_balancing_scheme = "EXTERNAL_MANAGED" protocol = "HTTP" # Vault serves plain HTTP; TLS terminates at the LB timeout_sec = 30 health_checks = [google_compute_health_check.vault.self_link] # GKE container-native NEG backends — one per zone where Vault pods are scheduled. # RATE balancing mode is required for NEGs with EXTERNAL_MANAGED load balancers. dynamic "backend" { for_each = data.google_compute_network_endpoint_group.vault_gke content { group = backend.value.self_link balancing_mode = "RATE" max_rate_per_endpoint = 100 } } log_config { enable = true sample_rate = 1.0 } } resource "google_compute_url_map" "vault" { name = "vault-urlmap" project = var.project_id default_service = google_compute_backend_service.vault.self_link } resource "google_compute_target_https_proxy" "vault" { name = "vault-https-proxy" project = var.project_id url_map = google_compute_url_map.vault.self_link ssl_certificates = [google_compute_managed_ssl_certificate.vault.self_link] } resource "google_compute_target_http_proxy" "vault_redirect" { name = "vault-http-proxy" project = var.project_id url_map = google_compute_url_map.vault_redirect.self_link } resource "google_compute_url_map" "vault_redirect" { name = "vault-urlmap-http-redirect" project = var.project_id default_url_redirect { https_redirect = true redirect_response_code = "MOVED_PERMANENTLY_DEFAULT" strip_query = false } } resource "google_compute_global_forwarding_rule" "vault_https" { name = "vault-fwd-https" project = var.project_id target = google_compute_target_https_proxy.vault.self_link ip_address = google_compute_global_address.vault.address port_range = "443" load_balancing_scheme = "EXTERNAL_MANAGED" } resource "google_compute_global_forwarding_rule" "vault_http" { name = "vault-fwd-http" project = var.project_id target = google_compute_target_http_proxy.vault_redirect.self_link ip_address = google_compute_global_address.vault.address port_range = "80" load_balancing_scheme = "EXTERNAL_MANAGED" } # ── Outputs ─────────────────────────────────────────────────────────────────── output "vault_lb_ip" { description = "Global IP for vault.neuralplatform.ai — set as DNS A record in Cloudflare (neuralplatform.ai zone)" value = google_compute_global_address.vault.address }