ibo-CI: PR-Preview-dev statt fixer Dev-Env, prod Auto-Deploy bei main-Merge
Some checks failed
Momentrum CI / Version (aus PR-ID / SHA) (push) Successful in 2s
Momentrum CI / Test (compile + pytest) (push) Failing after 43s
Momentrum CI / Build & Push image (push) Has been skipped
Momentrum CI / Helm lint + template (push) Successful in 9s
Momentrum CI / Deploy PROD (Image-Tag -> CD-Repo) (push) Has been skipped

Umstellung auf das kanban-Modell (PR-Preview-dev + prod), Zitadel-SSO vor beiden.
- CI: Job deploy-dev -> deploy; Write-back bei main-Merge jetzt nach app.yaml
  (prod) statt dev.yaml. dev braucht keinen Write-back (ApplicationSet liest den
  PR-Tag direkt).
- Chart: ingress.novncStripPrefixRef (Preview referenziert die geteilte externe
  strip-novnc-Middleware statt eine eigene anzulegen -> vom previews-AppProject
  erlaubt); priorityClassName (Preview-Pods sterben bei Memory-Pressure zuerst).
- RUNBOOK-ibo.md: auf PR-Preview-dev + prod-Auto-Deploy umgeschrieben.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
timu 2026-07-17 23:49:27 +02:00
parent 650d7f3394
commit d1ccf17b5f
6 changed files with 143 additions and 103 deletions

View File

@ -1,11 +1,14 @@
# Momentrum CI (Contabo-Gitea) — build · test · push · deploy(dev)
# Momentrum CI (Contabo-Gitea) — build · test · push · deploy(prod)
# Zielt auf das Gitea auf momentrum-k3s-01 (org: momentrum).
#
# Umgebungs-Modell fuer ibo (bewusst NUR dev+prod, keine PR-Previews):
# - dev = deployt AUTOMATISCH bei jedem main-Push (dieser Deploy-Step bumpt
# apps/internal/ibo/dev.yaml im CD-Repo -> ArgoCD synct dev).
# - prod = wird MANUELL promotet (Tag aus dev.yaml -> app.yaml committen,
# siehe infra/RUNBOOK-ibo.md). Die CI fasst prod NICHT an.
# Umgebungs-Modell fuer ibo (wie momentrum-kanban: PR-Preview-dev + prod):
# - dev = EPHEMERE PR-Previews. Kein Deploy-Step noetig: das ArgoCD-
# ApplicationSet (momentrum-deploy apps/internal/ibo/preview.yaml) liest
# den Tag pr-<nr>-<sha7> direkt aus dem PR -> https://ibo-pr-<nr>.dev.momentrum.de.
# PR braucht das Gitea-Label "preview" (Opt-in-Gate).
# - prod = deployt AUTOMATISCH bei jedem main-Push (Job "deploy" bumpt
# apps/internal/ibo/app.yaml im CD-Repo -> ArgoCD synct prod).
# Rollback = git revert im CD-Repo (siehe infra/RUNBOOK-ibo.md).
#
# Image-Tag ist immutable pro Commit:
# - Pull Request: pr-<nummer>-<shortsha>
@ -102,26 +105,26 @@ jobs:
helm lint "${{ env.CHART_PATH }}"
helm template ibo "${{ env.CHART_PATH }}" >/dev/null
# CD-Write-back: nur auf main. Bumpt den Image-Tag in apps/internal/ibo/dev.yaml
# im CD-Repo -> ArgoCD deployt DEV automatisch. Prod bleibt unberuehrt (Promote
# ist ein bewusster manueller Commit, siehe RUNBOOK). DEPLOY_TOKEN = Gitea-Token
# mit Write auf momentrum-deploy.
deploy-dev:
name: Deploy DEV (Image-Tag -> CD-Repo)
# CD-Write-back: nur auf main (= PR-Merge). Bumpt den Image-Tag in
# apps/internal/ibo/app.yaml im CD-Repo -> ArgoCD deployt PROD automatisch.
# PR-Previews deployen NICHT hierueber (die treibt das ApplicationSet direkt aus
# dem PR). DEPLOY_TOKEN = Gitea-Token mit Write auf momentrum-deploy.
deploy:
name: Deploy PROD (Image-Tag -> CD-Repo)
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [version, build-push, helm-validate]
steps:
- name: Write-back image.tag nach momentrum-deploy (dev.yaml)
- name: Write-back image.tag nach momentrum-deploy (app.yaml)
run: |
TAG="${{ needs.version.outputs.tag }}"
git clone -q "http://ci:${{ secrets.DEPLOY_TOKEN }}@100.111.27.99:3000/momentrum/momentrum-deploy.git" /tmp/deploy
cd /tmp/deploy
APP_FILE="apps/internal/ibo/dev.yaml"
APP_FILE="apps/internal/ibo/app.yaml"
grep -qE '^ tag: ' "$APP_FILE" || { echo "FEHLER: 'tag:'-Zeile nicht in $APP_FILE gefunden"; exit 1; }
sed -i "s|^ tag: .*| tag: ${TAG}|" "$APP_FILE"
git config user.email "ci@momentrum.local"
git config user.name "Momentrum CI"
git commit -am "ibo: deploy dev ${TAG}" || { echo "kein Change - Tag identisch"; exit 0; }
git commit -am "ibo: deploy prod ${TAG}" || { echo "kein Change - Tag identisch"; exit 0; }
git push origin HEAD:main
echo "Deployed dev tag ${TAG} -> momentrum-deploy"
echo "Deployed prod tag ${TAG} -> momentrum-deploy"

View File

@ -1,19 +1,17 @@
# Runbook — ibo (Immo-Bot) containerisieren, deployen, Zitadel-SSO davorschalten
# Runbook — ibo (Immo-Bot): CI/CD, PR-Preview-dev + prod, Zitadel-SSO
Immo-Bot = Flask-Web-App + Selenium-Chrome-Sidecar (noVNC-Live-Ansicht). Zwei
feste Umgebungen (KEINE PR-Previews):
Immo-Bot = Flask-Web-App + Selenium-Chrome-Sidecar (noVNC-Live-Ansicht).
Umgebungs-Modell **wie momentrum-kanban**: ephemere PR-Previews als „dev" + eine
stehende prod. Beide hinter Zitadel-SSO (die App selbst hat KEINE eigene Auth).
| Umgebung | Host | TLS-Secret | Deploy |
|----------|------------------------|--------------|------------------------------------------|
| dev | `dev.ibo.momentrum.de` | `ibo-dev-tls`| **automatisch** bei jedem main-Push (CI) |
| prod | `ibo.momentrum.de` | `ibo-tls` | **manuell promotet** (Tag-Copy, s. u.) |
| Umgebung | Host | SSO-Proxy | Deploy |
|----------|----------------------------------|-------------------|-------------------------------------------------|
| dev | `ibo-pr-<nr>.dev.momentrum.de` | generisches `dev-sso` | ephemer pro PR mit Label `preview` (ApplicationSet) |
| prod | `ibo.momentrum.de` | per-App `ibo-sso` | **automatisch** bei jedem main-Merge (CI → CD-Repo) |
Beide hinter demselben Zitadel-oauth2-proxy `ibo-sso`
(`cookie-domain .ibo.momentrum.de` deckt dev **und** prod ab).
Die Muster spiegeln kanban (CI/Chart/CD) und luxly-sso/dev-sso (oauth2-proxy).
Cluster-, Zitadel- und DNS-Schritte sind **manuell** — dieses Runbook ist die
Anleitung. Reihenfolge unten einhalten.
Die Muster spiegeln kanban/luxly (CI/Chart/CD/ApplicationSet) und dev-sso/ibo-sso
(oauth2-proxy). Cluster-, Zitadel- und DNS-Schritte sind **manuell** — dieses
Runbook ist die Anleitung. Reihenfolge unten einhalten.
---
@ -21,116 +19,130 @@ Anleitung. Reihenfolge unten einhalten.
```sh
cd projekte/ibo
git init && git add -A && git commit -m "ibo: containerize + CI + infra"
git add -A && git commit -m "ibo: PR-Preview-dev + prod, Zitadel-SSO"
git remote add origin momentrum-gitea:momentrum/ibo.git # SSH-Alias wie andere Repos
git push -u origin main # push-create legt momentrum/ibo an, falls aktiviert
git push -u origin main
```
**Gitea-Actions-Secrets** am Repo `momentrum/ibo` setzen (Settings → Actions → Secrets):
**Gitea-Actions-Secrets** am Repo `momentrum/ibo` (Settings → Actions → Secrets):
- `REGISTRY_USER`, `REGISTRY_TOKEN` — Push in die Gitea-Registry.
- `DEPLOY_TOKEN` — Gitea-Token mit **Write auf `momentrum/momentrum-deploy`**
(Write-back des dev-Image-Tags).
(Write-back des prod-Image-Tags bei main-Merge).
---
## 1. Zitadel: Redirect-URI ergaenzen (KEIN neuer Client)
## 1. Zitadel: Redirect-URIs (KEIN neuer Client)
`ibo-sso` nutzt — wie `luxly-sso` — den **bestehenden geteilten** Zitadel-Client
(K8s-Secret `oauth2-proxy-dev` in ns `iam`). Es ist **kein neuer Client** und
**kein neues Secret** noetig. Nur am vorhandenen Client im Zitadel-Console
(`https://auth.momentrum.de`) die Redirect-URI ergaenzen:
`ibo-sso` und `dev-sso` nutzen — wie `luxly-sso` — den **bestehenden geteilten**
Zitadel-Client (K8s-Secret `oauth2-proxy-dev` in ns `iam`). **Kein neuer Client,
kein neues Secret.** Nur am vorhandenen Client (`https://auth.momentrum.de`) die
Redirect-URI ergaenzen:
- Redirect-URI **hinzufuegen**: `https://sso.ibo.momentrum.de/oauth2/callback`
(EIN Login-Host `sso.ibo.momentrum.de` deckt per `cookie-domain .ibo.momentrum.de`
dev **und** prod ab. Wer prod spaeter mit eigenem Blast-Radius trennen will:
eigenen Client + eigenes SealedSecret anlegen und im `ibo-sso`-Deployment
referenzieren — die `oauth2-proxy-dev`-Secret-Refs dort ersetzen.)
- prod: `https://sso.ibo.momentrum.de/oauth2/callback` ← nur diese ist ibo-spezifisch
- dev (Previews): `https://sso.dev.momentrum.de/oauth2/callback` ← existiert i. d. R.
schon (kanban/luxly-Previews nutzen dasselbe dev-sso). Nichts zu tun, falls vorhanden.
---
## 2. oauth2-proxy `ibo-sso` (contabo-infra) — deployen
## 2. Cluster-Voraussetzungen (contabo-infra) — muessen laufen
Manifeste liegen in `contabo-infra/platform/manifests/ibo-sso/`
(Deployment/Service, Middlewares `oauth2-ibo-auth`/`oauth2-ibo-errors`, Ingress
`sso.ibo.momentrum.de`, oauth2-Passthrough-Route). Sie referenzieren das
bestehende Secret `oauth2-proxy-dev` + die ConfigMap `oauth2-proxy-dev-templates`
— **nichts einzusealen**.
Fuer **prod** (`platform/manifests/ibo-sso/`, ArgoCD-App `platform/apps/ibo-sso.yaml`):
- oauth2-proxy `ibo-sso` (Deployment/Service, ns `iam`).
- Middlewares `iam-oauth2-ibo-auth@kubernetescrd` / `iam-oauth2-ibo-errors@kubernetescrd`.
- Ingress `sso.ibo.momentrum.de` (Login-Host, ohne Auth davor).
- **Geteilte** stripPrefix-Middleware `iam-strip-novnc@kubernetescrd` (`strip-novnc.yaml`)
— die Previews referenzieren sie cross-namespace (s. §4).
Die ArgoCD-App `platform/apps/ibo-sso.yaml` wird vom platform-App-of-Apps
automatisch aufgenommen (gleiche Ablage wie `luxly-sso.yaml`) — committen &
pushen genuegt; alternativ einmalig `kubectl apply -f platform/manifests/ibo-sso/`.
Ausserdem ist das ibo-Repo in `platform/manifests/argocd-projects/internal.yaml`
(sourceRepos) bereits ergaenzt — sonst lehnt ArgoCD die App-Source ab.
Fuer **dev/Previews** (bereits vorhanden, von kanban/luxly geteilt):
- `dev-sso` (generischer oauth2-proxy `*.dev.momentrum.de`, Middlewares
`iam-oauth2-auth`/`iam-oauth2-errors`, Login `sso.dev.momentrum.de`).
- SealedSecret `gitea-appset-token` (ns `argocd`) — Gitea-Read fuer den PR-Generator.
- AppProject `previews` — erlaubt Source `momentrum/*` (deckt ibo ab) und
begrenzt Previews auf `preview-*`-Namespaces. **Blockt bewusst
traefik.io/Middleware im Preview-ns** → deshalb die geteilte `strip-novnc` in §2.
Ergebnis:
- Middlewares `iam-oauth2-ibo-auth@kubernetescrd` / `iam-oauth2-ibo-errors@kubernetescrd`
stehen bereit (die App-Ingresses referenzieren sie).
- `https://sso.ibo.momentrum.de` liefert die Login-Seite (kein Auth davor).
App-of-Apps nimmt `ibo-sso.yaml` automatisch auf — committen & pushen genuegt;
alternativ einmalig `kubectl apply -f platform/manifests/ibo-sso/`. Das ibo-Repo
ist in `platform/manifests/argocd-projects/internal.yaml` (sourceRepos) bereits
erlaubt (sonst lehnt ArgoCD die prod-App-Source ab).
---
## 3. DNS
A/AAAA-Records auf die Cluster-Ingress-IP zeigen lassen:
- `ibo.momentrum.de`
- `dev.ibo.momentrum.de`
- `sso.ibo.momentrum.de`
A/AAAA-Records auf die Cluster-Ingress-IP:
- `ibo.momentrum.de` (prod)
- `sso.ibo.momentrum.de` (prod-Login)
cert-manager (`letsencrypt-prod`, HTTP-01) stellt die Zertifikate `ibo-tls`,
`ibo-dev-tls`, `ibo-sso-tls` automatisch aus, sobald DNS steht.
Previews brauchen **keinen eigenen Record** — sie laufen unter dem bestehenden
Wildcard `*.dev.momentrum.de` (wie kanban/luxly). cert-manager
(`letsencrypt-prod`, HTTP-01) stellt `ibo-tls`, `ibo-sso-tls` und die per-Preview-
Certs (`ibo-pr-<nr>-tls`) automatisch aus, sobald DNS/Ingress stehen.
---
## 4. Deploy-Reihenfolge
## 4. CD-Apps im `momentrum-deploy` (bereits angelegt)
1. Repo gepusht (Schritt 0) → CI baut das erste Image und bumpt
`apps/internal/ibo/dev.yaml` (`image.tag`).
2. `ibo-sso` laeuft (Schritt 2), DNS steht (Schritt 3).
3. CD-Apps im `momentrum-deploy` committen: `apps/internal/ibo/dev.yaml` +
`apps/internal/ibo/app.yaml`. ArgoCD legt Namespace `apps-ibo` an und synct.
4. **Erstes Prod-Promote:** den von der CI in `dev.yaml` gesetzten `image.tag`
nach `app.yaml` kopieren (siehe unten) — sonst hat prod noch `tag: latest`.
- `apps/internal/ibo/app.yaml` — prod-Application (`ibo.momentrum.de`,
ns `apps-internal`, SSO `iam-oauth2-ibo-*`). Auto-Sync; `image.tag` bumpt die CI.
- `apps/internal/ibo/preview.yaml` — PR-Preview-ApplicationSet (Gitea-PR-Generator,
Label-Gate `preview`). Rendert ibos Chart aus dem **PR-Branch** und setzt pro PR:
Host `ibo-pr-<nr>.dev.momentrum.de`, `priorityClassName: preview`, gedeckelte
Resources (preview-ns-Quota: ≤2 CPU / 1536Mi Limits gesamt),
`ssoMiddlewares: iam-oauth2-errors,iam-oauth2-auth` (dev-sso) und
`novncStripPrefixRef: iam-strip-novnc@kubernetescrd` (statt eigener Middleware).
committen & pushen → ArgoCD legt die prod-App + das ApplicationSet an.
---
## 5. Prod promoten (Routine)
## 5. Deploy-Flows
Prod bekommt bewusst NUR den Tag, den man freigibt:
**dev / Preview (pro PR):**
1. PR gegen `main` oeffnen → CI baut `pr-<nr>-<sha7>` (Job build-push).
2. Am PR das Gitea-Label **`preview`** setzen (Opt-in-Gate = Concurrency-Deckel).
3. ArgoCD-ApplicationSet (Polling 120 s) legt `ibo-pr-<nr>` + ns
`preview-ibo-pr-<nr>` an → `https://ibo-pr-<nr>.dev.momentrum.de`.
4. PR schliessen/mergen oder Label entfernen → Application + Namespace kaskadieren
weg (finalizer + gemanagter Namespace, KEIN CreateNamespace).
```sh
cd momentrum-deploy
DEVTAG=$(grep -E '^ tag: ' apps/internal/ibo/dev.yaml | awk '{print $2}')
sed -i "s|^ tag: .*| tag: ${DEVTAG}|" apps/internal/ibo/app.yaml
git commit -am "ibo: promote ${DEVTAG} -> prod" && git push
```
**prod (bei main-Merge):**
- CI-Job `deploy` schreibt den neuen `image.tag` in `apps/internal/ibo/app.yaml`
zurueck → ArgoCD synct prod automatisch. Kein manueller Schritt.
- **Rollback:** `git revert` des CI-Commits im `momentrum-deploy` (ArgoCD synct
zurueck). Alternativ `image.tag` in `app.yaml` auf einen aelteren Tag setzen.
ArgoCD synct prod auf den neuen Tag. Rollback = `git revert` dieses Commits.
> Wer prod bewusst manuell freigeben will statt Auto-Deploy: den `deploy`-Job in
> `.gitea/workflows/momentrum-ci.yml` entfernen und den Tag per Hand nach
> `app.yaml` committen. Aktuell ist Auto-Deploy aktiv (wie kanban).
---
## 6. Browser-Live-Ansicht (noVNC)
Der Automations-Chrome laeuft im `selenium`-Sidecar; sein Bild wird per noVNC
gestreamt und in der Web-App eingebettet (Button „👁️ Browser live ansehen",
oeffnet auch automatisch beim Consent-Browser). Routing:
gestreamt und in der Web-App eingebettet (Button „👁️ Browser live ansehen").
Routing:
- App-Container → Chrome via `SELENIUM_REMOTE_URL=http://localhost:4444`.
- Client-Browser → `https://<host>/novnc/…` → Ingress-Pfad `/novnc`
→ stripPrefix-Middleware → Sidecar-Port 7900 (noVNC/websockify).
- Steuerbar durch die SSO-Cookie (gleicher Host, gleiche Middlewares).
- prod: chart-eigene Middleware `<ns>-ibo-novnc` (App-ns).
- Preview: geteilte `iam-strip-novnc` (weil das `previews`-Project eigene
Middlewares im Preview-ns blockt).
- Zugriff durch die SSO-Cookie (gleicher Host, gleiche Middleware-Kette).
Der Browser laeuft **serverseitig** im Container — es wird NICHT der lokale
Browser des Nutzers ferngesteuert (das ginge von einer gehosteten App aus nicht).
Browser des Nutzers ferngesteuert.
---
## 7. Break-glass (Notzugang)
Faellt Zitadel aus: die SSO-Middlewares temporaer aus `ingress.ssoMiddlewares`
im jeweiligen CD-App-YAML entfernen (die App selbst hat keine eigene Auth →
sie ist dann OFFEN). Nur kurz, danach sofort zuruecksetzen. Nie ungeschuetzt
lassen.
in `apps/internal/ibo/app.yaml` (prod) entfernen (die App selbst hat keine eigene
Auth → sie ist dann OFFEN). Nur kurz, danach sofort zuruecksetzen. Nie
ungeschuetzt lassen.
---
@ -139,10 +151,11 @@ lassen.
- [ ] `docker compose up -d` lokal → `http://localhost:5000` UI, „Browser live
ansehen" zeigt den Chrome im iframe (localhost:7900).
- [ ] `curl -s localhost:5000/healthz` → `{"ok":true}`.
- [ ] main-Push → CI gruen (version→test→build-push→helm-validate→deploy-dev),
`dev.yaml`-Tag gebumpt, ArgoCD rollt dev.
- [ ] `https://dev.ibo.momentrum.de` → Redirect zu `auth.momentrum.de`, nach
Login landet man in der App.
- [ ] In der App eingebettetes `/novnc/` zeigt den Live-Browser.
- [ ] `https://ibo.momentrum.de` nach Promote ebenso hinter Zitadel.
- [ ] PR + Label `preview` → CI gruen (version→test→build-push→helm-validate),
ArgoCD legt `ibo-pr-<nr>` an, `https://ibo-pr-<nr>.dev.momentrum.de`
redirected zu `auth.momentrum.de`, nach Login landet man in der App.
- [ ] Im Preview eingebettetes `/novnc/` zeigt den Live-Browser.
- [ ] PR schliessen → Preview + Namespace verschwinden (ArgoCD prune).
- [ ] main-Merge → CI-Job `deploy` bumpt `app.yaml`, ArgoCD rollt prod,
`https://ibo.momentrum.de` hinter Zitadel erreichbar.
- [ ] Ohne SSO-Session → Login-Redirect (kein rohes 401).

View File

@ -15,12 +15,19 @@ app.kubernetes.io/instance: {{ .Release.Name }}
{{- /*
Middleware-Kette fuer die Ingress-Annotation: erst die SSO-Middlewares aus dem
CD-Repo (errors VOR auth), dann die same-namespace stripPrefix fuer /novnc.
Traefik-Ingress-Refs sind "<namespace>-<name>@kubernetescrd".
CD-Repo (errors VOR auth), dann die stripPrefix fuer /novnc. Traefik-Ingress-Refs
sind "<namespace>-<name>@kubernetescrd".
Die stripPrefix-Middleware ist normalerweise die vom Chart im Release-Namespace
angelegte; ist novncStripPrefixRef gesetzt (Previews), wird stattdessen diese
EXTERNE (geteilte) Middleware referenziert und das Chart legt keine eigene an.
*/ -}}
{{- define "ibo.middlewares" -}}
{{- $mw := list -}}
{{- if .Values.ingress.ssoMiddlewares -}}{{- $mw = append $mw .Values.ingress.ssoMiddlewares -}}{{- end -}}
{{- if .Values.ingress.novncStripPrefixRef -}}
{{- $mw = append $mw .Values.ingress.novncStripPrefixRef -}}
{{- else -}}
{{- $mw = append $mw (printf "%s-%s-novnc@kubernetescrd" .Release.Namespace (include "ibo.name" .)) -}}
{{- end -}}
{{- join "," $mw -}}
{{- end -}}

View File

@ -17,6 +17,9 @@ spec:
labels:
{{- include "ibo.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
containers:
# --- Flask-Web-App ---------------------------------------------------
- name: app

View File

@ -1,8 +1,11 @@
{{- if .Values.ingress.enabled }}
{{- if and .Values.ingress.enabled (not .Values.ingress.novncStripPrefixRef) }}
# Strippt den /novnc-Prefix, bevor der Request an den Selenium-noVNC (7900) geht:
# der Ingress-Pfad /novnc/vnc.html -> selenium sieht /vnc.html, /novnc/websockify
# -> /websockify. Same-namespace, wird in _helpers.tpl an die Middleware-Kette
# der Ingress-Annotation angehaengt.
# NUR wenn ingress.novncStripPrefixRef leer ist — Previews referenzieren eine
# geteilte externe Middleware (iam-strip-novnc), weil das "previews"-AppProject
# das Anlegen von traefik.io/Middleware im Preview-ns blockt.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:

View File

@ -12,6 +12,11 @@ image:
# offener Consent-Browser) — mehrere Replicas wuerden ihn nicht teilen.
replicaCount: 1
# Previews setzen "preview" (niedrige PriorityClass, definiert in contabo-infra):
# unter Memory-Pressure auf der 12-GB-Box sterben Preview-Pods zuerst, nie Prod.
# Prod laesst das leer.
priorityClassName: ""
service:
# Nach aussen (ClusterIP) sichtbare Ports; targetPorts sind die Container-Ports.
appPort: 80
@ -41,12 +46,18 @@ ingress:
secretName: ibo-tls
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
# Zitadel-SSO davor (oauth2-proxy "ibo-sso" in contabo-infra). Reihenfolge:
# errors VOR auth, damit 401 zum Login-Redirect wird. Die stripPrefix-Middleware
# fuer /novnc haengt das Chart selbst hinten an (siehe _helpers.tpl).
# Vom CD-Repo gesetzt, z.B.:
# "iam-oauth2-ibo-errors@kubernetescrd,iam-oauth2-ibo-auth@kubernetescrd"
# Zitadel-SSO davor. Reihenfolge: errors VOR auth, damit 401 zum Login-Redirect
# wird. Die stripPrefix-Middleware fuer /novnc haengt das Chart hinten an
# (siehe _helpers.tpl). Vom CD-Repo gesetzt:
# prod -> "iam-oauth2-ibo-errors@kubernetescrd,iam-oauth2-ibo-auth@kubernetescrd" (per-App ibo-sso)
# preview -> "iam-oauth2-errors@kubernetescrd,iam-oauth2-auth@kubernetescrd" (generisches dev-sso)
ssoMiddlewares: ""
# Referenz auf eine EXTERNE /novnc-stripPrefix-Middleware ("<ns>-<name>@kubernetescrd").
# Leer = das Chart legt die Middleware selbst im Release-Namespace an (Prod/Default).
# Gesetzt = Chart legt KEINE eigene an, haengt stattdessen diese Referenz an die Kette.
# PR-Previews MUESSEN das setzen: das ArgoCD-"previews"-Project blockt das Anlegen von
# traefik.io/Middleware im Preview-ns (Anti-Auth-Faelschung) -> geteilte iam-strip-novnc.
novncStripPrefixRef: ""
resources:
app: