Files
Will Anderson 73b9095d83 migrate Terraform backend to GCS, remove dead Vault GCE nodes
Switch gcp/ backend from Cloudflare R2 (S3-compatible) to GCS — uses
Application Default Credentials automatically, no extra env vars needed.
State has been migrated to gs://neuron-785695-terraform-state/gcp/.

Remove GCE Vault node resources (vault-node-1/2/3) from vault-nodes.tf
and Terraform state. GKE Vault (Workload Identity + vault-unseal SA) has
been serving traffic since the NEG cutover; GCE nodes are confirmed dead.

Removed from state and config:
- google_compute_instance.vault_node (x3)
- google_compute_disk.vault_data (x3)
- google_compute_instance_group.vault (x3)
- google_compute_firewall.vault_iap_ssh / vault_raft / vault_api (GCE-targeted)
- google_storage_bucket_object.vault_startup
- google_storage_bucket_iam_member.vault_node_bucket_read
- google_project_iam_member.vault_node_{log_writer,metric_writer,compute_viewer}

Kept: KMS, vault-unseal SA, WI binding, NEG data sources, GKE firewall,
global LB (address, cert, backend service, url maps, proxies, fwd rules).
2026-05-05 10:38:22 -05:00

177 lines
6.7 KiB
Terraform

# ── 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
}