feat: switch Prosody to JWT auth (HS256, Embertime as issuer)
All checks were successful
deploy / deploy (push) Successful in 4s

Replaces the anonymous-OK setup with JWT-gated joins. Only participants
that Embertime invited get a valid token — random URL-guessers can no
longer enter rooms even if they discover the slug.

- ConfigMap: ENABLE_AUTH=1 + AUTH_TYPE=jwt + JWT_APP_ID=embertime
- 20-secrets.yaml.example: JWT_APP_SECRET placeholder with docs
- CLAUDE.md: documents the new auth model + rotation flow

Pipeline rolls config out; the secret itself stays out-of-band — admin
copies it from Embertime UI (Settings → Meeting-Server) or queries the
embertime DB directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dennis Paradzinski 2026-05-11 15:19:00 +02:00
parent d946046773
commit 8e76a96668
3 changed files with 30 additions and 5 deletions

View File

@ -39,9 +39,20 @@ Inter-Component-Auth über shared XMPP-Component-Secrets (im Kubernetes-Secret,
Danach: Pipeline rollt aus, in ~3 Min steht `https://meet.it.financeflow.de`.
## Auth-Modell (JWT, Stand 2026-05-11)
Prosody ist auf **`AUTH_TYPE=jwt`** (HS256) konfiguriert — Joins ohne signiertes Token werden abgelehnt. Embertime ist der einzige Token-Issuer:
- HMAC-Secret lebt in `app_settings.meeting_jwt_secret` (Embertime-DB)
- Wird auch im k8s-Secret `jitsi-secrets` als `JWT_APP_SECRET` benötigt — beide müssen identisch sein
- Embertime-Endpoint `GET /meetings/:id/join` mintet pro Teilnehmer + Meeting ein zeitlich begrenztes Token (gültig bis Meeting-Ende + 2h)
- Token-Payload enthält `room` (= room_slug), `context.user` (Display-Name + email + moderator-Flag)
Bei Secret-Rotation: neuer Wert über Embertime-Admin-UI sichtbar, dann `kubectl -n jitsi patch secret jitsi-secrets ...` + `kubectl -n jitsi rollout restart deployment` (sonst gilt noch der alte JWT_APP_SECRET in den laufenden Pods).
## Was NICHT machen
- Keine Authentifizierung aktivieren — der Witz ist, dass der Service ohne Login funktioniert. `ENABLE_AUTH=0` ist Pflicht.
- `ENABLE_AUTH=0` zurücksetzen — würde das ganze Auth-Modell unwirksam machen. Wenn du eine offene Instanz brauchst, lieber zweite Jitsi-Instanz auf anderem Subdomain.
- Keinen Jibri (Recording) ohne expliziten Auftrag — braucht extra Pod mit Chrome + viel mehr Ressourcen
- Kein Helm — bleibt beim raw-Manifest-Pattern wie Embertime
- Nicht `replicas > 1` für prosody/jicofo — beide sind stateful Single-Instance

View File

@ -22,11 +22,18 @@ data:
XMPP_SERVER: "prosody.jitsi.svc.cluster.local"
XMPP_BOSH_URL_BASE: "http://prosody.jitsi.svc.cluster.local:5280"
# === Auth disabled — anyone with the URL can start a room. That's the
# whole point of self-hosting (avoids the meet.jit.si Google/GitHub
# moderator gate). ===
ENABLE_AUTH: "0"
# === JWT-based auth — Prosody validates HS256 tokens signed by
# Embertime. Only invited participants get a valid token (with
# context.user populated, optional moderator flag). The shared HMAC
# secret lives in the Kubernetes Secret as JWT_APP_SECRET. Guests are
# disabled — a missing/invalid token means no entry. ===
ENABLE_AUTH: "1"
AUTH_TYPE: "jwt"
ENABLE_GUESTS: "0"
JWT_APP_ID: "embertime"
JWT_ACCEPTED_ISSUERS: "embertime"
JWT_ACCEPTED_AUDIENCES: "embertime"
TOKEN_AUTH_URL: ""
# === TLS handled by ingress cert-manager, not by the jitsi/web container ===
ENABLE_LETSENCRYPT: "0"

View File

@ -13,8 +13,15 @@ metadata:
namespace: jitsi
type: Opaque
stringData:
# Inter-component passwords — generate fresh via generate-secrets.sh
JICOFO_COMPONENT_SECRET: "REPLACE_WITH_32_RANDOM_CHARS"
JICOFO_AUTH_USER: "focus"
JICOFO_AUTH_PASSWORD: "REPLACE_WITH_32_RANDOM_CHARS"
JVB_AUTH_USER: "jvb"
JVB_AUTH_PASSWORD: "REPLACE_WITH_32_RANDOM_CHARS"
# HMAC key shared with Embertime — must match app_settings.meeting_jwt_secret
# in Embertime's DB. Get it from the Embertime UI (Settings → Meeting-Server
# → "Secret rotieren") OR query the DB directly with:
# kubectl -n embertime exec -it deploy/embertime-postgres -- \
# psql -U embertime -t -c "select meeting_jwt_secret from app_settings"
JWT_APP_SECRET: "REPLACE_WITH_VALUE_FROM_EMBERTIME"