From 2d6812f9517075f40c1937160c2f999cba049b44 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sun, 10 May 2026 00:06:40 +0000 Subject: [PATCH] =?UTF-8?q?fire-planner:=20dual=20ingress=20=E2=80=94=20/a?= =?UTF-8?q?pi/*=20unprotected,=20/=20behind=20Authentik?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SPA can't carry an Authentik session on its own fetch() XHRs in all cases (cross-origin redirect to authentik.viktorbarzin.me on a stale cookie returns HTML, fetch().json() parse fails). Splitting the ingress so /api/ paths skip forward-auth lets the React app talk to its API end-to-end. The browser still has to log in via Authentik to load the SPA at /. Verified end-to-end via chrome-service Playwright: dashboard load, scenario list, what-if run with real Monte Carlo, save-as-scenario round-trip, run-now on detail, delete — all pass. Co-Authored-By: Claude Opus 4.7 --- stacks/fire-planner/main.tf | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/stacks/fire-planner/main.tf b/stacks/fire-planner/main.tf index 9e777739..9d72a779 100644 --- a/stacks/fire-planner/main.tf +++ b/stacks/fire-planner/main.tf @@ -420,6 +420,26 @@ module "ingress" { } } +# Second ingress at the same host for the /api/ prefix WITHOUT Authentik +# forward-auth. The SPA loads under Authentik (main ingress at /), then its +# fetch() XHRs hit /api/* directly — forward-auth on /api/* would 302 the +# XHR to a cross-origin Authentik login page, which fetch().json() can't +# parse. App-layer bearer auth still gates writes (POST/PATCH/DELETE on +# scenarios, /recompute, /simulate); read endpoints are open. Acceptable +# for a personal tool whose only data is anonymous numeric projections. +module "ingress_api" { + source = "../../modules/kubernetes/ingress_factory" + dns_type = "none" + namespace = kubernetes_namespace.fire_planner.metadata[0].name + name = "fire-planner-api" + host = "fire-planner" # share effective_host with main ingress + service_name = "fire-planner" + port = 8080 + ingress_path = ["/api/"] + tls_secret_name = var.tls_secret_name + protected = false +} + # Plan-time read of the ESO-created K8s Secret for Grafana datasource # password. First-apply gotcha: must # `terragrunt apply -target=kubernetes_manifest.db_external_secret` so