feat(forte-drop): wildcard IngressRoute for per-slug drop subdomains
All checks were successful
AI Code Review / ai-review (pull_request) Has been skipped

No forte-helm chart change needed after all. The forteapp chart emits one exact
Host(`drop.forteapps.net`) route (apex: admin + /api + public /shared). Add an
ADDITIVE standalone IngressRoute for the per-slug wildcard *.drop.forteapps.net,
pointing at the SAME chart service (forte-drop-app:3000 — whose targetPort is the
auth sidecar when auth is on), so forte drop subdomains flow through the sidecar and
are Forte-login gated exactly like the admin root.

priority:1 (LOW) is load-bearing: Traefik orders routers by rule-length by default,
and this regex is longer than Host(`mcp.drop.forteapps.net`) — without the explicit
low priority it would STEAL mcp.drop (and apex) traffic into the web pod. priority:1
guarantees the exact Host() routers (mcp release + chart apex) always win.

Traefik v3 (chart 28.x) HostRegexp = Go RE2; verify the rendered router against
mcp./www./app./apex/<real-slug> before prod. Uses the wildcard-drop-forteapps-net-tls
secret from the Certificate added in the same branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sten
2026-06-10 09:53:10 +02:00
parent 44ae8e0da6
commit fcd8f99a52
2 changed files with 40 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
# Wildcard routing for per-slug forte drops: <slug>.drop.forteapps.net -> the forte-drop
# web pod. The forteapp chart only emits a single exact Host(`drop.forteapps.net`) route
# (the apex: admin + /api + public /shared drops), so this ADDITIVE IngressRoute adds the
# wildcard. Kept in launchpad (forte-drop-specific) rather than the shared forteapp chart.
#
# It targets the SAME service the chart's route does — forte-drop-app:3000 — whose
# targetPort is the auth sidecar (service.yaml: targetPort = auth.sidecarPort when auth is
# on). So wildcard subdomains flow service:3000 -> sidecar -> app, i.e. they are Forte-login
# gated exactly like the admin root. A forteOnly drop is therefore never served un-gated.
#
# priority: 1 (intentionally LOW). Traefik orders routers by rule-length by default, and the
# regex string is longer than Host(`mcp.drop.forteapps.net`); without an explicit low
# priority this regex would OUTRANK and STEAL mcp.drop.forteapps.net (and the apex) into the
# web pod. priority:1 guarantees the exact Host() routers (mcp release, chart apex) always win;
# only real per-slug subdomains fall through to here. The app's reserved-slug check
# (mcp/www/api/admin/app) is a second line of defence.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: forte-drop-subdomains
namespace: forte-drop
labels:
app.kubernetes.io/name: forte-drop
app.kubernetes.io/part-of: apps
app.kubernetes.io/managed-by: argocd
spec:
entryPoints:
- websecure
routes:
# Traefik v3 (chart 28.x) HostRegexp takes a Go RE2 pattern. Verify the rendered
# router against mcp./www./app./apex/<real-slug> before relying on it in prod.
- match: HostRegexp(`^[a-z0-9-]+\.drop\.forteapps\.net$`)
kind: Rule
priority: 1
services:
- name: forte-drop-app
port: 3000
tls:
secretName: wildcard-drop-forteapps-net-tls

View File

@@ -6,3 +6,4 @@ resources:
- forte-drop-pdb.yaml - forte-drop-pdb.yaml
- forte-drop-secrets-sealed.yaml - forte-drop-secrets-sealed.yaml
- wildcard-drop-tls-certificate.yaml - wildcard-drop-tls-certificate.yaml
- forte-drop-subdomains-ingressroute.yaml