From 5b16aebdcb06c604bc8b0479e0c54a28c37a4776 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Sun, 26 Apr 2026 01:09:44 -0500 Subject: [PATCH] =?UTF-8?q?Remove=20stage=20environment=20from=20GCP=20?= =?UTF-8?q?=E2=80=94=20staging=20is=20local=20only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- servers/gcp/cloud-run.tf | 108 --------------------------------- servers/gcp/load-balancer.tf | 105 -------------------------------- servers/gcp/outputs.tf | 13 ---- servers/gcp/service-account.tf | 9 --- 4 files changed, 235 deletions(-) diff --git a/servers/gcp/cloud-run.tf b/servers/gcp/cloud-run.tf index 047fb88..9f1f77c 100644 --- a/servers/gcp/cloud-run.tf +++ b/servers/gcp/cloud-run.tf @@ -357,111 +357,3 @@ resource "google_cloud_run_v2_service" "prod_apac" { depends_on = [google_project_iam_member.marketing_secret_accessor] } -# ── Stage — us-central1 ─────────────────────────────────────────────────────── -# min_instances=0 to save cost on staging. -# Cloudflare Access handles auth in front; Cloud Run itself is open so the LB -# health checks pass without credentials. - -resource "google_cloud_run_v2_service" "stage" { - name = "marketing-stage" - location = "us-central1" - project = var.project_id - - ingress = "INGRESS_TRAFFIC_ALL" - - labels = merge(local.run_labels, { - "environment" = "stage" - }) - - template { - service_account = google_service_account.marketing.email - - scaling { - min_instance_count = 0 - max_instance_count = 10 - } - - containers { - image = local.image - - resources { - limits = { - cpu = "1" - memory = "512Mi" - } - cpu_idle = true - } - - env { - name = "NODE_ENV" - value = "production" - } - env { - name = "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY" - value = local.stripe_publishable_key - } - - env { - name = "STRIPE_SECRET_KEY" - value_source { - secret_key_ref { - secret = "stripe-secret-key" - version = "latest" - } - } - } - env { - name = "STRIPE_WEBHOOK_SECRET" - value_source { - secret_key_ref { - secret = "stripe-webhook-secret" - version = "latest" - } - } - } - env { - name = "STRIPE_PRICE_PROFESSIONAL" - value_source { - secret_key_ref { - secret = "stripe-price-professional" - version = "latest" - } - } - } - env { - name = "STRIPE_PRICE_FOUNDING" - value_source { - secret_key_ref { - secret = "stripe-price-founding" - version = "latest" - } - } - } - - ports { - container_port = 3000 - name = "http1" - } - - startup_probe { - http_get { - path = "/api/health" - port = 3000 - } - initial_delay_seconds = 10 - timeout_seconds = 5 - period_seconds = 10 - failure_threshold = 5 - } - } - - max_instance_request_concurrency = 1000 - } - - traffic { - type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" - percent = 100 - } - - depends_on = [google_project_iam_member.marketing_secret_accessor] -} diff --git a/servers/gcp/load-balancer.tf b/servers/gcp/load-balancer.tf index 0aa21aa..7e62e18 100644 --- a/servers/gcp/load-balancer.tf +++ b/servers/gcp/load-balancer.tf @@ -35,17 +35,6 @@ resource "google_compute_region_network_endpoint_group" "prod_apac" { } } -resource "google_compute_region_network_endpoint_group" "stage" { - name = "marketing-neg-stage" - network_endpoint_type = "SERVERLESS" - region = "us-central1" - project = var.project_id - - cloud_run { - service = google_cloud_run_v2_service.stage.name - } -} - # ── Cloud Armor Security Policy ─────────────────────────────────────────────── # Applied to the backend service. Rules evaluated top-down (lowest priority wins). @@ -173,30 +162,6 @@ resource "google_compute_backend_service" "prod" { } } -# ── Stage Backend Service ───────────────────────────────────────────────────── - -resource "google_compute_backend_service" "stage" { - name = "marketing-backend-stage" - project = var.project_id - load_balancing_scheme = "EXTERNAL_MANAGED" - protocol = "HTTPS" - timeout_sec = 30 - - # Cloud Armor on stage too - security_policy = google_compute_security_policy.marketing.self_link - - enable_cdn = false # CDN off for stage — we want fresh responses always - - backend { - group = google_compute_region_network_endpoint_group.stage.self_link - } - - log_config { - enable = true - sample_rate = 1.0 - } -} - # ── SSL Certificates ────────────────────────────────────────────────────────── # google_compute_managed_ssl_certificate — Google-managed, auto-renewed. # Provisioning requires DNS A records pointing to the LB IP (chicken-and-egg: @@ -214,15 +179,6 @@ resource "google_compute_managed_ssl_certificate" "prod" { } } -resource "google_compute_managed_ssl_certificate" "stage" { - name = "marketing-cert-stage" - project = var.project_id - - managed { - domains = ["stage.neurontechnologies.ai"] - } -} - # ── Prod URL Map — host-based routing ──────────────────────────────────────── # One global IP handles all three services via Host header routing. # - neurontechnologies.ai / www. → marketing (default) @@ -324,64 +280,3 @@ resource "google_compute_global_forwarding_rule" "prod_http" { load_balancing_scheme = "EXTERNAL_MANAGED" } -# ── Stage URL Map ───────────────────────────────────────────────────────────── - -resource "google_compute_url_map" "stage" { - name = "marketing-urlmap-stage" - project = var.project_id - default_service = google_compute_backend_service.stage.self_link -} - -# ── Stage HTTPS Target Proxy ────────────────────────────────────────────────── - -resource "google_compute_target_https_proxy" "stage" { - name = "marketing-https-proxy-stage" - project = var.project_id - url_map = google_compute_url_map.stage.self_link - ssl_certificates = [google_compute_managed_ssl_certificate.stage.self_link] -} - -# ── Stage HTTP → HTTPS redirect ─────────────────────────────────────────────── - -resource "google_compute_url_map" "stage_http_redirect" { - name = "marketing-urlmap-stage-http-redirect" - project = var.project_id - - default_url_redirect { - https_redirect = true - redirect_response_code = "MOVED_PERMANENTLY_DEFAULT" - strip_query = false - } -} - -resource "google_compute_target_http_proxy" "stage" { - name = "marketing-http-proxy-stage" - project = var.project_id - url_map = google_compute_url_map.stage_http_redirect.self_link -} - -# ── Stage Global Forwarding Rules ───────────────────────────────────────────── -# Separate global IP for stage so DNS is independent. - -resource "google_compute_global_address" "stage" { - name = "marketing-ip-stage" - project = var.project_id -} - -resource "google_compute_global_forwarding_rule" "stage_https" { - name = "marketing-fwd-stage-https" - project = var.project_id - target = google_compute_target_https_proxy.stage.self_link - ip_address = google_compute_global_address.stage.address - port_range = "443" - load_balancing_scheme = "EXTERNAL_MANAGED" -} - -resource "google_compute_global_forwarding_rule" "stage_http" { - name = "marketing-fwd-stage-http" - project = var.project_id - target = google_compute_target_http_proxy.stage.self_link - ip_address = google_compute_global_address.stage.address - port_range = "80" - load_balancing_scheme = "EXTERNAL_MANAGED" -} diff --git a/servers/gcp/outputs.tf b/servers/gcp/outputs.tf index 1ab4933..dfa06fb 100644 --- a/servers/gcp/outputs.tf +++ b/servers/gcp/outputs.tf @@ -7,19 +7,12 @@ # www.neurontechnologies.ai → prod_lb_ip # api.neurontechnologies.ai → prod_lb_ip # accounts.neurontechnologies.ai → prod_lb_ip -# -# Stage: stage.neurontechnologies.ai → stage_lb_ip (separate IP) output "prod_lb_ip" { description = "Global anycast IP for all prod services (marketing, accounts, api)" value = google_compute_global_address.prod.address } -output "stage_lb_ip" { - description = "Global anycast IP for the staging load balancer" - value = google_compute_global_address.stage.address -} - output "prod_ssl_cert_name" { description = "Marketing SSL cert (check provisioning status in GCP console)" value = google_compute_managed_ssl_certificate.prod.name @@ -35,11 +28,6 @@ output "api_ssl_cert_name" { value = google_compute_managed_ssl_certificate.api.name } -output "stage_ssl_cert_name" { - description = "Stage SSL cert" - value = google_compute_managed_ssl_certificate.stage.name -} - output "marketing_service_account_email" { description = "Marketing Cloud Run SA" value = google_service_account.marketing.email @@ -76,7 +64,6 @@ output "cloud_run_services" { marketing_us = google_cloud_run_v2_service.prod_us.uri marketing_eu = google_cloud_run_v2_service.prod_eu.uri marketing_apac = google_cloud_run_v2_service.prod_apac.uri - marketing_stage = google_cloud_run_v2_service.stage.uri accounts_us = google_cloud_run_v2_service.accounts_us.uri accounts_eu = google_cloud_run_v2_service.accounts_eu.uri accounts_apac = google_cloud_run_v2_service.accounts_apac.uri diff --git a/servers/gcp/service-account.tf b/servers/gcp/service-account.tf index 1c0692e..d97fc5d 100644 --- a/servers/gcp/service-account.tf +++ b/servers/gcp/service-account.tf @@ -79,15 +79,6 @@ resource "google_cloud_run_v2_service_iam_member" "prod_apac_public" { member = "allUsers" } -resource "google_cloud_run_v2_service_iam_member" "stage_public" { - project = var.project_id - location = "us-central1" - name = google_cloud_run_v2_service.stage.name - role = "roles/run.invoker" - member = "allUsers" - # Note: Cloudflare Access enforces auth in front of stage. -} - # Accounts resource "google_cloud_run_v2_service_iam_member" "accounts_us_public" { project = var.project_id