backup old wiki
This commit is contained in:
parent
6bcbe9cc9e
commit
b1247b4720
117
docs/oldwiki/authentik.md
Normal file
117
docs/oldwiki/authentik.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# Authentik als Einladungs- und Self-Registration-Layer vor MAS in ESS Community
|
||||||
|
|
||||||
|
## Kurzurteil
|
||||||
|
|
||||||
|
Ja — in deinem Setup ist **Authentik** technisch sinnvoll einsetzbar, aber **nicht als Ersatz für den Matrix Authentication Service**, sondern **als Upstream-OIDC-Provider vor MAS**. Das ist der sauberste Weg, weil Synapse heute eine stabile, vereinfachte Integration mit MAS hat, ESS Community zusätzliche MAS-Konfiguration ausdrücklich über `matrixAuthenticationService.additional` vorsieht, und MAS jede OIDC-konforme Upstream-Identitätsquelle unterstützt. Für ein ESS-Deployment mit delegierter Authentifizierung ist das deutlich kohärenter als eine Direktanbindung von Synapse an Authentik vorbei. citeturn31view0turn7view2turn14view1turn23search0
|
||||||
|
|
||||||
|
Wichtig ist aber die Abgrenzung: Wenn dein einziges Problem wirklich nur lautet „im Admin-Frontend kann ich keine Registration Tokens mehr klicken“, dann **brauchst du Authentik nicht zwingend**. MAS hat weiterhin eine Admin-API mit Endpunkten für User-Registration-Tokens; der fehlende Komfort liegt also eher in der Oberfläche als in der Funktion selbst. Die API ist mit `urn:mas:admin` abgesichert und kann sowohl interaktiv als auch automatisiert benutzt werden. citeturn19search0turn28search0turn28search1turn28search2
|
||||||
|
|
||||||
|
## Warum Authentik hier die bessere Plattform sein kann
|
||||||
|
|
||||||
|
Der Mehrwert von Authentik entsteht dann, wenn du **mehr als nur ein Token-Feld** willst: Einladungen, Self-Service-Enrolment, E-Mail-Verifikation, Policies, Gruppen-Zuweisung, später vielleicht weitere Login-Quellen hinter derselben Oberfläche. Authentik kann selbst als OpenID Provider auftreten, aber auch als Relying Party gegenüber anderen OAuth/OIDC-Quellen arbeiten; MAS sieht dann nur noch **eine** saubere OIDC-Oberfläche, während Authentik die eigentliche Onboarding- und Policy-Logik kapselt. Das passt sehr gut zu MAS, weil MAS nach oben bewusst nur OIDC unterstützt und SAML/LDAP nicht selbst als Upstream sprechen will. citeturn21view0turn21view3turn14view1
|
||||||
|
|
||||||
|
Für dein Ziel „potenzielle Anwender sollen sich selbst registrieren können“ ist der entscheidende Unterschied: Bei MAS-Registration-Tokens autorisierst du eine **Matrix-Registrierung**; bei Authentik autorisierst du zunächst eine **Identität im IdP**, und MAS übernimmt diese Identität anschließend per OIDC und legt daraus den Matrix-Account an. Das ist architektonisch stärker, weil dieselbe Identität später auch für andere Dienste nutzbar wird. MAS kann beim Upstream-Login den Matrix-Localpart, Display Name und E-Mail aus Claims übernehmen; für neue Nutzer gibt es dabei sogar einen expliziten Bestätigungs- bzw. Attribut-Import-Schritt. citeturn24search0turn14view0
|
||||||
|
|
||||||
|
## Wann Authentik nicht nötig ist
|
||||||
|
|
||||||
|
Wenn du ausschließlich einen „Einladungs-Code“ für Matrix brauchst und keinerlei separates Identitätsmanagement, dann ist die schlankere Lösung wahrscheinlich: **bei MAS bleiben und die Registration-Tokens per Admin-API verwalten**. Dafür brauchst du keinen zusätzlichen Dienst, keine zweite Postgres-Anwendung und keine zweite Policy-Oberfläche. Das ist betriebsärmer und passt gut zu kleinen Community-Setups. citeturn19search0turn28search0turn28search2
|
||||||
|
|
||||||
|
Sobald du aber Dinge wie diese willst, kippt die Bewertung klar zugunsten von Authentik: verschiedene Onboarding-Flows, Einladungs-Links statt nackter Codes, E-Mail-Verifikation, Domain-Allow-Lists, Gruppen-Zuweisung, zentrale MFA-Politik oder später externe Identity-Sources. Authentik bringt dafür sowohl vorgefertigte Einladungs-Blueprints als auch Enrolment-Flows mit und kann bei Bedarf eigene Expression Policies für restriktivere Zulassungslogik einsetzen. citeturn21view1turn21view2turn30search3
|
||||||
|
|
||||||
|
## Empfohlene Zielarchitektur
|
||||||
|
|
||||||
|
Die von mir empfohlene Zielarchitektur ist:
|
||||||
|
|
||||||
|
**Element Web / Clients → MAS → Authentik → Benutzerquelle(n)**
|
||||||
|
|
||||||
|
Synapse bleibt dabei an MAS delegiert. Das ist genau der Pfad, den die Synapse- und MAS-Dokumentation heute unterstützen: Synapse integriert stabil mit MAS, und MAS kann wiederum Upstream-OIDC-Provider sprechen. Eine direkte Synapse-OIDC-Integration mit Authentik ist zwar technisch dokumentiert, wäre in deinem ESS/MAS-Setup aber die weniger saubere Variante, weil du damit an der in ESS bereits vorgesehenen Delegationsschicht vorbeikonfigurierst. citeturn31view0turn14view2turn14view1turn7view2
|
||||||
|
|
||||||
|
Für Authentik selbst ist das Standardmaterial: auf Kubernetes per Helm deployen, in Produktion ein echtes PostgreSQL verwenden statt der Demo-Datenbank, und E-Mail konfigurieren, wenn du Einladungen oder Verifikations-Mails nutzen willst. Das ist wichtig, weil Authentik-Einladungen und E-Mail-basierte Enrolment-Flows ohne Mailtransport ihren eigentlichen Nutzen verlieren. citeturn34view0turn25search1
|
||||||
|
|
||||||
|
Ein entscheidender UX-Punkt: Wenn in MAS genau **ein** Upstream-Provider konfiguriert ist und die lokale Passwortdatenbank deaktiviert wird, startet MAS den Upstream-Authentifizierungsfluss automatisch. Damit verhält sich das System für Endnutzer fast so, als wäre Authentik „direkt“ integriert, obwohl MAS weiterhin die Matrix-native Auth-Schicht bleibt. citeturn26view0
|
||||||
|
|
||||||
|
## Konkrete Integration in ESS und FluxCD
|
||||||
|
|
||||||
|
Der erste praktische Schritt ist, Authentik als eigene GitOps-Anwendung in Kubernetes einzuführen. Offiziell ist dafür das Helm-Chart vorgesehen; produktiv sollte die Datenbank extern bzw. operator-basiert laufen, und Mail sollte von Anfang an mitgedacht werden. Danach erzeugst du in Authentik eine **Application + OAuth2/OIDC Provider**-Kombination. Das ist der von Authentik empfohlene Weg zur Erstellung eines OIDC-Providers. citeturn34view0turn35view0
|
||||||
|
|
||||||
|
Für den OIDC-Provider in Authentik verwendest du als Redirect-URI **nicht** die Synapse-Callback-URL aus der direkten Synapse-Dokumentation, sondern die von MAS erwartete Upstream-Callback-URL. MAS verlangt für Upstream-Provider eine stabile ULID als Provider-ID und verwendet daraus die Callback-URL `https://<auth-service-domain>/upstream/callback/<id>`. Optional kannst du zusätzlich die Backchannel-Logout-URL `https://<auth-service-domain>/upstream/backchannel-logout/<id>` hinterlegen. Authentik unterstützt für OIDC-Anwendungen Front- und Back-Channel-Logout, sofern der Provider entsprechend konfiguriert ist. citeturn14view1turn26view3turn35view1
|
||||||
|
|
||||||
|
In ESS selbst musst du dafür **keinen Chart forken**. Die vorgesehene Stelle ist `matrixAuthenticationService.additional`. Dort gibst du MAS die Upstream-OIDC-Konfiguration und schaltest die lokale Passwortdatenbank ab, wenn Authentik der alleinige Eintrittspunkt werden soll. Genau dafür ist die ESS-Advanced-Dokumentation da. citeturn7view2
|
||||||
|
|
||||||
|
Ein praktikabler MAS-Werteblock für deine GitOps-Struktur sieht so aus:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
matrixAuthenticationService:
|
||||||
|
additional:
|
||||||
|
10-authentik-upstream.yaml:
|
||||||
|
config: |
|
||||||
|
passwords:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
account:
|
||||||
|
password_registration_enabled: false
|
||||||
|
|
||||||
|
upstream_oauth2:
|
||||||
|
providers:
|
||||||
|
- id: 01JVXXXXXXXXXXXXXXXAUTHN
|
||||||
|
issuer: "https://auth.example.com/application/o/matrix-mas/"
|
||||||
|
human_name: "Community Login"
|
||||||
|
client_id: "mas-community"
|
||||||
|
client_secret: "AUS_SOPS_SECRET"
|
||||||
|
token_endpoint_auth_method: client_secret_post
|
||||||
|
scope: "openid profile email"
|
||||||
|
fetch_userinfo: true
|
||||||
|
on_backchannel_logout: logout_browser_only
|
||||||
|
|
||||||
|
claims_imports:
|
||||||
|
localpart:
|
||||||
|
action: require
|
||||||
|
template: "{{ user.preferred_username }}"
|
||||||
|
# Nur für Bestandskonten und nur nach Pilotphase:
|
||||||
|
# on_conflict: set
|
||||||
|
|
||||||
|
displayname:
|
||||||
|
action: force
|
||||||
|
template: "{{ user.name }}"
|
||||||
|
|
||||||
|
email:
|
||||||
|
action: force
|
||||||
|
template: "{{ user.email }}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Die inhaltliche Grundlage dafür kommt direkt aus den MAS-Upstream-OIDC-Dokumenten: Provider-`id` als ULID, `issuer`, `client_id`, `client_secret`, Scope, optionale UserInfo-Nutzung und Claim-Mapping für `localpart`, `displayname` und `email`. ESS injiziert genau solche zusätzlichen MAS-Dateien über `matrixAuthenticationService.additional`. citeturn14view1turn14view0turn13view5turn7view2
|
||||||
|
|
||||||
|
Für das eigentliche Onboarding in Authentik hast du zwei gute Varianten. Wenn du das MAS-Token-Modell möglichst ähnlich nachbauen willst, nimmst du **Invitations**. Authentik kann Einladungs-URLs an konkrete Empfänger senden oder generische Einladungslinks bereitstellen, bei denen Benutzer ihre Credentials selbst festlegen. Wenn du eher echte Self-Service-Registrierung willst, nimmst du einen Enrolment-Flow, optional mit E-Mail-Verifikation. Beide Muster sind offiziell dokumentiert; es gibt sogar vorgefertigte Blueprints für invitation-based enrollment und Beispiel-Flows für Enrolment mit oder ohne E-Mail-Verifikation. citeturn21view1turn21view2
|
||||||
|
|
||||||
|
Wenn du bei der Benutzerführung in Element noch glatter werden willst, kannst du optional in Element Web `sso_redirect_options` setzen, damit Nutzer auf der Login- oder Welcome-Seite sofort in den OIDC-/SSO-Flow gehen. Das ist kein Muss — MAS kann bei einem einzigen Upstream-Provider ohnehin automatisch weiterleiten — aber es verbessert den Eindruck eines „SSO-only“-Setups. citeturn15view4turn26view0
|
||||||
|
|
||||||
|
Ein optionaler Element-Web-Block dafür wäre:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sso_redirect_options": {
|
||||||
|
"on_login_page": true,
|
||||||
|
"on_welcome_page": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Risiken und Fallstricke
|
||||||
|
|
||||||
|
Der heikelste Punkt ist die **Abbildung auf bestehende Matrix-Konten**. MAS kann Upstream-Identitäten an vorhandene lokale Nutzer binden, wenn der gemappte `localpart` passt. Standardmäßig verweigert MAS diese Verknüpfung aber; dafür gibt es `claims_imports.localpart.on_conflict` mit Werten wie `set`, `add` oder `replace`. Die Dokumentation warnt ausdrücklich davor, dass das bei unsauberem Mapping ein Account-Takeover-Risiko werden kann. In der Praxis heißt das: `on_conflict` nur dann einschalten, wenn du sicher garantieren kannst, dass Authentik-`preferred_username` oder ein anderes Attribut **eindeutig und dauerhaft** dem gewünschten Matrix-Localpart entspricht. citeturn26view2turn14view0
|
||||||
|
|
||||||
|
Der zweite Betriebsfallstrick ist GitOps-spezifisch: Änderungen und Ergänzungen im `upstream_oauth2.providers`-Block synchronisiert MAS beim Start in seine Datenbank, **Entfernungen** aber nicht automatisch. Wenn du einen Provider wieder herausnimmst oder umbenennst, brauchst du zusätzlich `mas-cli config sync --prune`. Für FluxCD ist das wichtig, weil „Config aus Git gelöscht“ hier nicht automatisch „Provider aus MAS-DB gelöscht“ bedeutet. citeturn27search1turn13view5
|
||||||
|
|
||||||
|
Der dritte Punkt betrifft Logout-Semantik. Sowohl MAS als auch Authentik können OIDC-Logout verarbeiten, aber du solltest den Modus bewusst wählen. `logout_all` in MAS ist am konsequentesten, kann aber auch Sessions beenden, die aus derselben Upstream-Sitzung stammen und über andere Flows erzeugt wurden. `logout_browser_only` ist meist die konservativere Wahl für einen ersten Rollout. Auf Authentik-Seite kannst du zusätzlich vollständiges Single Logout aktivieren, wenn Logout aus einer Anwendung auch die Authentik-Sitzung selbst und andere verbundene Anwendungen beenden soll. citeturn26view0turn35view1
|
||||||
|
|
||||||
|
Falls du Authentik doch nicht einführst und stattdessen bei MAS-Registration-Tokens bleibst, solltest du den ESS-Hinweis ernst nehmen: `account.password_registration_email_required: false` darf auf einem öffentlich föderierenden System nur zusammen mit Einschränkungen wie `registration_token_required: true` benutzt werden, sonst läufst du direkt in Missbrauch und Spam. MAS selbst dokumentiert dieselben Schalter im `account`-Block: Passwort-Registrierung ist standardmäßig aus, E-Mail-Pflicht standardmäßig an, Registration-Token-Pflicht standardmäßig aus. citeturn7view2turn13view0turn13view1turn13view2
|
||||||
|
|
||||||
|
## Praktische Entscheidung
|
||||||
|
|
||||||
|
Wenn dein Zielbild lautet **„Einladungen, Self-Service, Verifikation, Gruppen, spätere Erweiterbarkeit“**, dann ist meine klare Empfehlung: **Authentik vor MAS**. Das ist in ESS Community sauber integrierbar, nutzt die offiziell vorgesehenen Konfigurationspfade und hält Synapse in der heute empfohlenen MAS-Architektur. citeturn7view2turn31view0turn14view1
|
||||||
|
|
||||||
|
Wenn dein Zielbild dagegen nur lautet **„ich will wieder Registration Tokens vergeben können, aber ohne zweiten IdP zu betreiben“**, dann ist die wirtschaftlichere Lösung sehr wahrscheinlich: **MAS Admin API automatisieren statt Authentik einführen**. Funktional ist das möglich; der fehlende Baustein ist nur die Bedienoberfläche, nicht die darunterliegende Token-Funktion. citeturn19search0turn28search0turn28search2
|
||||||
|
|
||||||
|
## Offene Punkte und Grenzen
|
||||||
|
|
||||||
|
Die produktseitigen Integrationsfragen sind gut durch die offiziellen Dokumentationen abgedeckt. Was ich in diesem Bericht bewusst generisch gehalten habe, sind deine **konkreten Datei- und Pfadnamen im GitOps-Repo** sowie die **genaue Secret-Aufteilung** zwischen ConfigMap und SOPS-Secret. Die technische Empfehlung steht trotzdem fest: MAS bleibt die Matrix-Schicht, Authentik wird der Upstream-IdP, und die Integration erfolgt über `matrixAuthenticationService.additional` in ESS. citeturn7view2turn14view1
|
||||||
327
docs/oldwiki/fix report mrtc.md
Normal file
327
docs/oldwiki/fix report mrtc.md
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
# MISSING_MATRIX_RTC_TRANSPORT in ESS 26.4.0: Ursachenanalyse und vollständiger Fix
|
||||||
|
|
||||||
|
**Die Ursache ist Hypothese 1: `wellKnownDelegation.enabled: false` ist der Kill-Switch.** In genau dieser Konfiguration schreibt das ESS-Chart den Schlüssel `org.matrix.msc4143.rtc_foci` normalerweise automatisch in das an `https://axion1337.chat/.well-known/matrix/client` ausgelieferte JSON-Dokument – sobald `wellKnownDelegation.enabled: true` **und** `matrixRTC.enabled: true` gesetzt sind. Mit `wellKnownDelegation: false` fällt dieses Dokument komplett weg. Element Web hat damit keinen Discovery-Pfad zur LiveKit-Instanz auf `mrtc.axion1337.chat`, und Matrix-JS-SDK wirft genau deshalb `MISSING_MATRIX_RTC_TRANSPORT`. Hypothese 2 (Synapse-Custom-Keys sind bogus) ist ebenfalls korrekt. Hypothese 4 (Element Web braucht explizites `rtc_foci`) ist **falsch** – Element Web liest `rtc_foci` ausschließlich aus Well-Known, niemals aus `config.json`. Hypothese 5 ist ein *sekundäres* Thema: LiveKit UDP-Ports müssen offen sein, aber der Fehler `MISSING_MATRIX_RTC_TRANSPORT` entsteht ausschließlich aus der Discovery, nicht aus Medien-Erreichbarkeit.
|
||||||
|
|
||||||
|
## Wie die Fehlerkette konkret abläuft
|
||||||
|
|
||||||
|
Element Web ruft beim Start eines Anrufs intern zwei Discovery-Pfade auf: `GET /_matrix/client/v1/rtc/transports` gegen Synapse (MSC4143, ab Synapse 1.140) und als Fallback `GET https://<serverName>/.well-known/matrix/client`, wo der Schlüssel `org.matrix.msc4143.rtc_foci` erwartet wird. Das ESS-Chart befüllt **beide** Pfade automatisch, sobald `matrixRTC.enabled: true` ist: In `wellKnownDelegation` wird das `rtc_foci`-Array injiziert, in Synapse wird der `matrix_rtc.transports`-Block in die `homeserver.yaml` gemerged (chart-intern, siehe ess-helm Changelog Eintrag #855: *"Configure experimental MSC4143 advertisement in Synapse when MatrixRTC is enabled. This is in addition to the MSC4143 advertisement on the client well-known endpoint for now, but it is expected to replace it in time."*). **Beide Mechanismen werden durch `wellKnownDelegation.enabled: false` nicht vollständig deaktiviert** – die Synapse-Seite wird zwar weiter gesetzt, aber weil kein Well-Known am Apex existiert, kann Element Web den Homeserver gar nicht über `default_server_name` auflösen und daher auch den Transport-Endpunkt nicht konsistent nutzen. Resultat: leere Transport-Liste, Fehler ausgelöst.
|
||||||
|
|
||||||
|
Ein korrektes `/.well-known/matrix/client` sieht so aus (das ist exakt, was das Chart ausliefern würde):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"m.homeserver": { "base_url": "https://matrix.axion1337.chat" },
|
||||||
|
"m.identity_server": { "base_url": "https://vector.im" },
|
||||||
|
"org.matrix.msc4143.rtc_foci": [
|
||||||
|
{ "type": "livekit",
|
||||||
|
"livekit_service_url": "https://mrtc.axion1337.chat" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Schlüsselname ist **`org.matrix.msc4143.rtc_foci`** (MSC-Prefix, kein `m.rtc_foci`). Das Value-Objekt hat zwingend `type: "livekit"` und `livekit_service_url: "https://<matrixRTC.ingress.host>"`.
|
||||||
|
|
||||||
|
## Warum die Custom-Synapse-Values aktuell wirkungslos sind
|
||||||
|
|
||||||
|
Die Keys `matrix_rtc_enabled` und `matrix_rtc_uri` **existieren in Synapse nicht**. Synapse kennt für MatrixRTC genau zwei Dinge: einen `experimental_features`-Block (`msc3266_enabled`, `msc4140_enabled`, `msc4222_enabled`, und implementierungsabhängig `msc4143_enabled`) und einen Top-Level-Block `matrix_rtc.transports:` für den neuen `/v1/rtc/transports`-Endpunkt. Das ESS-Chart setzt diese **automatisch**, sobald `matrixRTC.enabled: true` ist. Synapse ignoriert unbekannte Top-Level-Keys in der `homeserver.yaml` stillschweigend; der Container crasht nicht, aber es passiert auch exakt gar nichts. Der ganze `rtc-config`-Block muss raus. Der `url-previews`-Block ist dagegen legitim – die Keys `url_preview_enabled`, `url_preview_ip_range_blacklist`, `max_spider_size` sind echte Synapse-Optionen.
|
||||||
|
|
||||||
|
## Der eigentliche Grund für die "ACME Race Condition"
|
||||||
|
|
||||||
|
Das Problem war **nicht** ein Bug, sondern eine vorhersagbare Fehlkonfiguration: Beide Ingresses (Element Web und wellKnownDelegation) forderten über die `cert-manager.io/cluster-issuer`-Annotation **jeweils ein eigenes TLS-Secret** für denselben Host `axion1337.chat` an. Cert-manager erzeugt dann zwei `Certificate`-Objekte mit unterschiedlichen `secretName`s → zwei `Order`-Objekte → HTTP-01-Solver-Ingresses überschreiben sich gegenseitig → Let's-Encrypt-Rate-Limit schlägt zu (5 duplicate certs / 7 Tage). Siehe cert-manager Issue #2342 und Discussion #3511: *"If both ingresses have their own secret to save the certificate tls, cert-manager runs havoc and exhausts the ACME limit very quickly."* Die saubere Lösung ist, dass genau **eine** Zertifikat-Quelle für `axion1337.chat` existiert.
|
||||||
|
|
||||||
|
Das ESS-Chart selbst erwartet, dass `elementWeb.ingress.host` **nicht** gleich `serverName` ist. Der Standard-Pattern ist: Element Web auf `chat.<apex>` bzw. `app.<apex>`, Well-Known auf dem Apex, und eine optionale `baseDomainRedirect.url` leitet `/` auf dem Apex zu Element Web weiter.
|
||||||
|
|
||||||
|
## Fix 1 (empfohlen): Element Web auf Subdomain umziehen
|
||||||
|
|
||||||
|
Das ist die Lösung, für die das Chart designt ist, und erfordert genau eine DNS-Änderung sowie YAML-Anpassungen.
|
||||||
|
|
||||||
|
### DNS-Voraussetzungen
|
||||||
|
|
||||||
|
| Record | Typ | Ziel | Zweck |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `axion1337.chat` | A/AAAA | öffentliche IP des K3s-Nodes | Apex: Well-Known + Cert für Matrix-Server-Delegation |
|
||||||
|
| `matrix.axion1337.chat` | A/AAAA | K3s-Node-IP | Synapse |
|
||||||
|
| `account.axion1337.chat` | A/AAAA | K3s-Node-IP | Matrix Authentication Service |
|
||||||
|
| `mrtc.axion1337.chat` | A/AAAA | K3s-Node-IP | LiveKit-Signaling + lk-jwt-service |
|
||||||
|
| `chat.axion1337.chat` | A/AAAA | K3s-Node-IP | **NEU**: Element Web |
|
||||||
|
| `admin.axion1337.chat` | A/AAAA | K3s-Node-IP | Element Admin |
|
||||||
|
|
||||||
|
### Angepasster HelmRelease (`apps/production/element-server-suite.yaml`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: matrix-stack
|
||||||
|
namespace: matrix
|
||||||
|
spec:
|
||||||
|
interval: 1h
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: matrix-stack
|
||||||
|
version: "26.4.0"
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: element-ess-oci
|
||||||
|
namespace: flux-system
|
||||||
|
valuesFrom:
|
||||||
|
- kind: ConfigMap
|
||||||
|
name: ess-synapse-custom
|
||||||
|
valuesKey: values.yaml
|
||||||
|
- kind: ConfigMap
|
||||||
|
name: ess-element-custom
|
||||||
|
valuesKey: values.yaml
|
||||||
|
- kind: Secret
|
||||||
|
name: ess-mas-values-secret
|
||||||
|
valuesKey: values.yaml
|
||||||
|
values:
|
||||||
|
serverName: axion1337.chat
|
||||||
|
certManager:
|
||||||
|
clusterIssuer: letsencrypt-prod
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
synapse:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: matrix.axion1337.chat
|
||||||
|
|
||||||
|
matrixAuthenticationService:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: account.axion1337.chat
|
||||||
|
|
||||||
|
matrixRTC:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: mrtc.axion1337.chat
|
||||||
|
# SFU public-IP override empfohlen, falls der Node hinter NAT steht
|
||||||
|
# und STUN die falsche Adresse zurückgibt:
|
||||||
|
# sfu:
|
||||||
|
# useStunToDiscoverPublicIP: false
|
||||||
|
# manualIP: "<public-IP-of-node>"
|
||||||
|
|
||||||
|
elementWeb:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: chat.axion1337.chat # <- NICHT mehr der Apex
|
||||||
|
|
||||||
|
elementAdmin:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: admin.axion1337.chat
|
||||||
|
|
||||||
|
wellKnownDelegation:
|
||||||
|
enabled: true # <- zurück auf true (Default)
|
||||||
|
# Optional: Redirect vom Apex "/" auf Element Web.
|
||||||
|
# Das Chart-Feature kam in 26.x hinzu; falls dein konkreter Wert-Key
|
||||||
|
# fehlt, siehe Fix 2 (eigene IngressRoute) als sichere Alternative.
|
||||||
|
baseDomainRedirect:
|
||||||
|
url: https://chat.axion1337.chat
|
||||||
|
```
|
||||||
|
|
||||||
|
Mit diesem Setup beansprucht **genau ein** Chart-erzeugter Ingress den Apex `axion1337.chat`, nämlich der der `wellKnownDelegation`. Es gibt nur ein Zertifikat, keine Race Condition. Element Web läuft auf `chat.axion1337.chat` und bekommt sein eigenes, konfliktfreies Cert.
|
||||||
|
|
||||||
|
### Bereinigter Synapse-ConfigMap (`apps/production/custom-configs/synapse-values.yaml`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ess-synapse-custom
|
||||||
|
namespace: matrix
|
||||||
|
data:
|
||||||
|
values.yaml: |
|
||||||
|
synapse:
|
||||||
|
logging:
|
||||||
|
rootLevel: INFO
|
||||||
|
levelOverrides:
|
||||||
|
synapse.media.url_previewer: DEBUG
|
||||||
|
additional:
|
||||||
|
# RTC-Block ENTFERNT: matrix_rtc_enabled / matrix_rtc_uri sind keine
|
||||||
|
# gültigen Synapse-Keys. Das ESS-Chart setzt matrix_rtc.transports und
|
||||||
|
# die nötigen experimental_features automatisch, wenn matrixRTC.enabled=true.
|
||||||
|
1-url-previews:
|
||||||
|
config: |
|
||||||
|
url_preview_enabled: true
|
||||||
|
url_preview_ip_range_blacklist:
|
||||||
|
- '127.0.0.0/8'
|
||||||
|
- '10.0.0.0/8'
|
||||||
|
- '172.16.0.0/12'
|
||||||
|
- '192.168.0.0/16'
|
||||||
|
- '100.64.0.0/10'
|
||||||
|
- '192.0.0.0/24'
|
||||||
|
- '169.254.0.0/16'
|
||||||
|
- '192.88.99.0/24'
|
||||||
|
- '198.18.0.0/15'
|
||||||
|
- '192.0.2.0/24'
|
||||||
|
- '198.51.100.0/24'
|
||||||
|
- '203.0.113.0/24'
|
||||||
|
- '224.0.0.0/4'
|
||||||
|
- '::1/128'
|
||||||
|
- 'fe80::/10'
|
||||||
|
- 'fc00::/7'
|
||||||
|
- '2001:db8::/32'
|
||||||
|
- 'ff00::/8'
|
||||||
|
- 'fec0::/10'
|
||||||
|
max_spider_size: 10M
|
||||||
|
```
|
||||||
|
|
||||||
|
Wichtige Details zum `additional`-Mechanismus: die Keys werden **alphabetisch sortiert** gemerged, daher die `1-`/`2-`-Namenskonvention. Arrays werden ersetzt, nicht zusammengeführt.
|
||||||
|
|
||||||
|
### Element-Web-ConfigMap (`apps/production/custom-configs/element-values.yaml`)
|
||||||
|
|
||||||
|
Hier ist **keine** RTC-spezifische Änderung nötig. Element Web hat gemäß `element-web/docs/config.md` keinen `rtc_foci`-Key und entdeckt den Transport ausschließlich über Well-Known. Der optionale `element_call`-Block steuert nur Branding und Verhalten:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ess-element-custom
|
||||||
|
namespace: matrix
|
||||||
|
data:
|
||||||
|
values.yaml: |
|
||||||
|
elementWeb:
|
||||||
|
additional:
|
||||||
|
config.json: |
|
||||||
|
{
|
||||||
|
"brand": "aXion1337.Chat",
|
||||||
|
"element_call": {
|
||||||
|
"brand": "aXion1337 Call",
|
||||||
|
"use_exclusively": true
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"feature_video_rooms": true,
|
||||||
|
"feature_element_call_video_rooms": true
|
||||||
|
},
|
||||||
|
"show_labs_settings": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`use_exclusively: true` entfernt die Legacy-Jitsi-Option aus dem UI, sodass Anrufe garantiert über MatrixRTC/LiveKit laufen.
|
||||||
|
|
||||||
|
## Fix 2 (Alternative): Apex manuell splitten per Traefik IngressRoute
|
||||||
|
|
||||||
|
Falls `baseDomainRedirect` in deiner 26.4.0-Revision nicht greift oder du Element Web auf dem Apex behalten willst, ersetze beide Chart-Ingresses durch eine **einzige Traefik IngressRoute mit einem einzigen Certificate**. Dadurch sieht cert-manager nur noch eine Quelle für `axion1337.chat`, und Traefik routet Pfad-basiert.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# apps/production/apex-ingress.yaml
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: axion-apex-tls
|
||||||
|
namespace: matrix
|
||||||
|
spec:
|
||||||
|
secretName: axion-apex-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- axion1337.chat
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: axion-apex
|
||||||
|
namespace: matrix
|
||||||
|
spec:
|
||||||
|
entryPoints: [websecure]
|
||||||
|
tls:
|
||||||
|
secretName: axion-apex-tls
|
||||||
|
routes:
|
||||||
|
# Höchste Priorität: /.well-known/matrix/* -> wellKnownDelegation-Service
|
||||||
|
- match: Host(`axion1337.chat`) && PathPrefix(`/.well-known/matrix`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 100
|
||||||
|
services:
|
||||||
|
- name: matrix-stack-well-known-delegation # ggf. Service-Namen mit `kubectl get svc -n matrix` verifizieren
|
||||||
|
port: 8080
|
||||||
|
# Niedrigere Priorität: alles andere -> Element Web
|
||||||
|
- match: Host(`axion1337.chat`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 10
|
||||||
|
services:
|
||||||
|
- name: matrix-stack-element-web
|
||||||
|
port: 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Dazu muss in der HelmRelease die automatische Chart-Ingress-Erzeugung für diese beiden Komponenten unterbunden werden – setze `wellKnownDelegation.ingress.className: "none"` bzw. `elementWeb.ingress.className: "none"` oder setze die `host`-Werte auf Dummy-Hostnames, sodass die Chart-Ingresses nicht denselben Apex beanspruchen. Fix 1 ist wegen geringerer Komplexität klar zu bevorzugen.
|
||||||
|
|
||||||
|
## Netzwerk- und Firewall-Anforderungen für LiveKit
|
||||||
|
|
||||||
|
**Das ist der nächste Stolperstein nach dem Well-Known-Fix.** Die HTTPS-Ingress auf `mrtc.axion1337.chat` terminiert nur **Signaling (WSS auf TCP 443)** und die lk-jwt-service-Endpunkte `/sfu/get`, `/get_token`, `/healthz`. WebRTC-Medien laufen **nicht** über den Ingress, sondern direkt zum Node auf UDP/TCP-NodePorts.
|
||||||
|
|
||||||
|
Öffne auf deiner K3s-Node-Firewall (und im Router/Cloud-Security-Group):
|
||||||
|
|
||||||
|
| Port | Protokoll | Standard ESS CE | Zweck |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 80, 443 | TCP | — | Ingress + ACME HTTP-01 |
|
||||||
|
| `rtcMuxedUdp` NodePort | **UDP** | 30002 (CE) / 30882 (Pro) | **Kritisch**: WebRTC-Medien (UDP-Mux). Ohne das: keine Audio/Video-Daten |
|
||||||
|
| `rtcTcp` NodePort | TCP | 30881 | ICE/TCP-Fallback für Clients ohne UDP |
|
||||||
|
| `turn` NodePort | UDP | 30004 | Nur falls `matrixRTC.sfu.exposedServices.turn.enabled: true` |
|
||||||
|
| `turnTLS` Port | TCP | 31443 oder 443 | Nur falls TURN/TLS aktiv; braucht SNI-Passthrough und eigenes Hostname |
|
||||||
|
|
||||||
|
Ermittle die tatsächlichen NodePorts per `kubectl get svc -n matrix | grep rtc`. Wenn dein Node hinter NAT steht und LiveKits STUN-basierte Public-IP-Erkennung die falsche Adresse zurückliefert, setze zusätzlich:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
matrixRTC:
|
||||||
|
sfu:
|
||||||
|
useStunToDiscoverPublicIP: false
|
||||||
|
manualIP: "<deine-öffentliche-IP>"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verifikationsschritte
|
||||||
|
|
||||||
|
Nach Reconcile (`flux reconcile helmrelease matrix-stack -n matrix`) diese vier Tests durchführen:
|
||||||
|
|
||||||
|
**1. Well-Known für Matrix-Client liefert rtc_foci:**
|
||||||
|
```bash
|
||||||
|
curl -sS https://axion1337.chat/.well-known/matrix/client | jq .
|
||||||
|
# Erwartung: JSON mit "m.homeserver" UND "org.matrix.msc4143.rtc_foci"
|
||||||
|
# das livekit_service_url == "https://mrtc.axion1337.chat" enthält.
|
||||||
|
|
||||||
|
curl -sS https://axion1337.chat/.well-known/matrix/server | jq .
|
||||||
|
# Erwartung: {"m.server": "matrix.axion1337.chat:443"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. lk-jwt-service und LiveKit-Signaling sind erreichbar:**
|
||||||
|
```bash
|
||||||
|
curl -i https://mrtc.axion1337.chat/healthz
|
||||||
|
# Erwartung: HTTP/1.1 200 OK
|
||||||
|
|
||||||
|
curl -i https://mrtc.axion1337.chat/sfu/get
|
||||||
|
# Erwartung: HTTP/1.1 405 Method Not Allowed (akzeptiert nur POST)
|
||||||
|
|
||||||
|
curl -i -H "Connection: Upgrade" -H "Upgrade: websocket" \
|
||||||
|
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
|
||||||
|
-H "Sec-WebSocket-Version: 13" \
|
||||||
|
https://mrtc.axion1337.chat/
|
||||||
|
# Erwartung: HTTP/1.1 101 Switching Protocols (WebSocket-Upgrade)
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Synapse bietet den MSC4143-Endpunkt an:**
|
||||||
|
```bash
|
||||||
|
TOKEN="<gültiges-access-token>"
|
||||||
|
curl -sS -H "Authorization: Bearer $TOKEN" \
|
||||||
|
https://matrix.axion1337.chat/_matrix/client/v1/rtc/transports | jq .
|
||||||
|
# Erwartung: {"transports":[{"type":"livekit","livekit_service_url":"https://mrtc.axion1337.chat"}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. UDP-Medien kommen an:** In Element Web Call starten → im Chrome/Firefox-DevTools unter Netzwerk → WS prüfen, dass `wss://mrtc.axion1337.chat/rtc?access_token=...` einen `101`-Upgrade bekommt; unter `chrome://webrtc-internals` nach ICE-Candidate-Paaren mit Status `succeeded` und Typ `host/srflx` schauen. Falls nur Signaling, aber kein Media: UDP-NodePort auf Firewall prüfen.
|
||||||
|
|
||||||
|
## ACME-Race dauerhaft vermeiden
|
||||||
|
|
||||||
|
Merksatz: **Ein Hostname ⇒ genau ein `Certificate`-Objekt ⇒ genau ein `secretName`.** Drei betriebliche Strategien:
|
||||||
|
|
||||||
|
- **Subdomain-Trennung (Fix 1):** Jede Chart-Komponente bekommt einen eigenen FQDN, jeder FQDN genau ein Cert. Keine Kollision möglich. Das ist die vom Chart vorgesehene Form.
|
||||||
|
- **Geteiltes Secret:** Wenn zwei Ingresses denselben Host tragen müssen, trägt nur **einer** die `cert-manager.io/cluster-issuer`-Annotation. Beide referenzieren `spec.tls[].secretName` auf dasselbe Secret. Traefik wählt das Zertifikat korrekt aus.
|
||||||
|
- **DNS-01 statt HTTP-01:** Löst den Solver-Ingress-Konflikt grundsätzlich, weil kein zweiter Ingress erzeugt wird. Setzt DNS-Provider-Credentials im ClusterIssuer voraus.
|
||||||
|
|
||||||
|
## Vom Benutzer übersehene Chart-Werte
|
||||||
|
|
||||||
|
Außer den oben beschriebenen Korrekturen sind diese Keys erwähnenswert, falls du feintunen willst. `matrixRTC.hostAliases` ist ein dokumentierter Workaround gegen Cluster-interne DNS-Probleme, wenn der lk-jwt-service-Pod den Homeserver-Apex bzw. Synapse über den Ingress-Controller statt direkt erreichen muss. `matrixRTC.sfu.exposedServices.<name>.portType` akzeptiert `NodePort`, `HostPort` oder `LoadBalancer` – für bare-metal K3s ohne externen LB ist `NodePort` richtig. `matrixRTC.sfu.additional."user-config.yaml".config` erlaubt rohes LiveKit-YAML für Spezialfälle (STUN-Server, Codecs). `wellKnownDelegation.additional.client` / `.server` / `.element` erlauben, in die erzeugten JSON-Dokumente zusätzliche Felder einzumischen – normalerweise nicht nötig, aber nützlich für föderative Sonderfälle.
|
||||||
|
|
||||||
|
## Fazit
|
||||||
|
|
||||||
|
Der eigentliche Defekt war ein einziger Kippschalter: `wellKnownDelegation.enabled: false` hat den einzig existierenden Discovery-Kanal für den LiveKit-Focus gekappt. Der darum herum gebaute Custom-Synapse-Block ist ein Red Herring – die zugehörigen Schlüssel existieren in Synapse schlicht nicht und werden ignoriert. Die ursprünglich empfundene ACME-Race ist kein Bug des Charts, sondern die vorhersagbare Folge davon, dass zwei Chart-erzeugte Ingresses (Element Web **auf dem Apex** plus Well-Known) jeweils ein eigenes Let's-Encrypt-Zertifikat für denselben Host anforderten. Sobald Element Web nach `chat.axion1337.chat` wandert und Well-Known wieder aktiv ist, produziert das Chart automatisch das korrekte `org.matrix.msc4143.rtc_foci`-Feld, injiziert den `matrix_rtc.transports`-Block in Synapse, und Element Call funktioniert – vorausgesetzt die UDP-NodePort-Firewall ist offen, was nach dem Discovery-Fix der zweite Punkt auf der Prüfliste ist.
|
||||||
12083
docs/oldwiki/home.md
Normal file
12083
docs/oldwiki/home.md
Normal file
File diff suppressed because it is too large
Load Diff
498
docs/oldwiki/invitereg.md
Normal file
498
docs/oldwiki/invitereg.md
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
# Invite-basierte Selbstregistrierung mit MAS in ESS Community unter Ansible und FluxCD
|
||||||
|
|
||||||
|
## Zusammenfassung
|
||||||
|
|
||||||
|
Für ein entity["company","Element","matrix software company"]-basiertes ESS-Community-Deployment mit aktivem Matrix Authentication Service ist eine invite-basierte Selbstregistrierung **ohne Authentik** sauber umsetzbar. Der belastbare Weg ist: **MAS-Registrierung aktivieren, Registrierungstoken erzwingen, Tokens über die MAS Admin API erzeugen, und Standard-Onboarding über Synapse `auto_join_rooms` abbilden**. In MAS-/MSC3861-Setups sind die alten Synapse-Mechanismen für Registration Tokens bzw. Shared-Secret-Registration nicht mehr der richtige Pfad: Die Synapse-Registration-Token-API ist in diesem Modus deaktiviert, ebenso die Shared-Secret-Registration-API; die offizielle Automationsoberfläche für externe Tools ist stattdessen die MAS Admin API. citeturn1view2turn20view1turn26search11turn26search5turn35view0
|
||||||
|
|
||||||
|
Für die Zuweisung zu Räumen und Spaces gilt: **MAS-Claims sind für Identitätsattribute gedacht, nicht für Raum-/Space-Mitgliedschaften**. Der robuste Standard ist daher eine Zweiteilung: **allgemeine Onboarding-Räume und Spaces über Synapse `auto_join_rooms`**, und **feingranulare, zielgruppenspezifische Mitgliedschaften über einen kleinen Post-Registration-Provisioner oder ein Synapse-Modul** über `on_user_registration` bzw. `on_user_login`. Gruppen/Communities sind heute kein sinnvolles Ziel mehr, weil Synapse diese Funktion deprecated und anschließend entfernt hat; für aktuelle Deployments solltest du konsequent mit **Spaces + Rooms** arbeiten. citeturn16view0turn16view1turn16view2turn34view0turn35view0turn17search0turn17search2
|
||||||
|
|
||||||
|
Für GitOps empfehle ich eine klare Trennung zwischen **statischer Konfiguration** und **operativem Invite-Zustand**. Statisch in Git/SOPS/Flux gehören: MAS-Account-Settings, SMTP-Daten, der MAS-Admin-OAuth-Client und optionale Onboarding-Policies. **Kurzlebige Einmal-Tokens** sollten dagegen in der Regel **nicht** als dauerhafter Desired State in Git geführt werden, sondern bei Bedarf über die MAS Admin API erzeugt, per E-Mail verschickt und nur optional als Audit-Record abgelegt werden. Das passt deutlich besser zu FluxCD als das “GitOpsen” flüchtiger Einladungen. Die optionale LiveKit-/Element-Call-Schicht ist für den Registrierungsfluss architektonisch unabhängig. citeturn20view1turn23view0turn23view3turn25search0turn25search13
|
||||||
|
|
||||||
|
## Zielbild und Architektur
|
||||||
|
|
||||||
|
Die offizielle ESS-Dokumentation unterstützt zusätzliche Konfiguration für Synapse, MAS, Element Web und MatrixRTC/LiveKit jeweils über `additional`-Blöcke. MAS läuft dabei neben Synapse und spricht mit Synapse über den dedizierten `matrix_authentication_service`-Mechanismus; Synapse 1.136+ führt diese Integration als stabile Konfiguration. Für dein Ziel bedeutet das: ESS/Helm liefert die Plattform, MAS erzwingt die Token-basierte Registrierung, Synapse übernimmt Mitgliedschaften, und Element Web kann optional eine eigene Landing-/Invite-Seite anzeigen. citeturn1view2turn1view5turn31view1turn35view0turn24search0
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph GitOps["GitOps-Steuerung"]
|
||||||
|
A[Ansible]
|
||||||
|
F[FluxCD]
|
||||||
|
G[Git Repository]
|
||||||
|
S[SOPS Secrets]
|
||||||
|
A --> G
|
||||||
|
S --> G
|
||||||
|
F --> G
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph K8s["Kubernetes / ESS Helm"]
|
||||||
|
HR[HelmRelease matrix-stack]
|
||||||
|
EW[Element Web]
|
||||||
|
MAS[Matrix Authentication Service]
|
||||||
|
SYN[Synapse]
|
||||||
|
PG[(PostgreSQL)]
|
||||||
|
SMTP[SMTP]
|
||||||
|
MOD[Optional: Post-Registration Provisioner / Synapse-Modul]
|
||||||
|
LK[Optional: LiveKit / Element Call]
|
||||||
|
end
|
||||||
|
|
||||||
|
G --> HR
|
||||||
|
HR --> EW
|
||||||
|
HR --> MAS
|
||||||
|
HR --> SYN
|
||||||
|
HR --> PG
|
||||||
|
HR --> LK
|
||||||
|
|
||||||
|
MAS --> PG
|
||||||
|
SYN --> PG
|
||||||
|
MAS --> SMTP
|
||||||
|
MAS <--> SYN
|
||||||
|
EW --> MAS
|
||||||
|
EW --> SYN
|
||||||
|
|
||||||
|
A -->|MAS Admin API| MAS
|
||||||
|
A -->|E-Mail Einladung| User[Neuer Benutzer]
|
||||||
|
User -->|Invite-Link + Registration Token| EW
|
||||||
|
User -->|Registrierung| MAS
|
||||||
|
MAS -->|User-Provisionierung| SYN
|
||||||
|
SYN -->|auto_join_rooms| User
|
||||||
|
MOD -->|join/invite per Synapse Admin API| SYN
|
||||||
|
```
|
||||||
|
|
||||||
|
Die praktikabelste Zielarchitektur ist deshalb: **Invite-Mail → MAS Token-Registierung → Synapse-Provisionierung → automatisches Standard-Onboarding via `auto_join_rooms` → optionaler Fein-Provisioner für zusätzliche Spaces/Räume**. Für Spaces ist wichtig: Synapse behandelt Spaces “unter der Haube” als Räume, daher können Space-Aliasse in `auto_join_rooms` verwendet werden. **Automatisch erzeugen** kann Synapse über `autocreate_auto_join_rooms` jedoch **keine Spaces**; Spaces müssen also vorher existieren. citeturn16view0turn16view1turn16view5
|
||||||
|
|
||||||
|
Die Optionen lassen sich so einordnen:
|
||||||
|
|
||||||
|
| Option | Bewertung | Stärken | Schwächen | Geeignet für |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| MAS Registration Tokens | **Empfohlen** | Nativ im MAS-Stack, sauber mit ESS/MAS, externe Tooling-Anbindung über Admin API | Keine offizielle, dokumentierte “Einladungs-E-Mail-Engine” für Invite-Links; Token-Versand musst du selbst automatisieren | ESS Community mit FluxCD/Ansible citeturn20view1turn12view0turn37view1turn1view2 |
|
||||||
|
| Authentik Invitations | Möglich, aber hier unnötig | Fertiges Invite-/Enrollment-Modell, URL-basierte Invitations | Zusätzlicher IdP-Layer, mehr bewegliche Teile, für dein Ziel kein Muss | Wenn ohnehin zentraler OIDC-IdP Standard ist citeturn36search0turn36search1 |
|
||||||
|
| Manuelle Admin-Erstellung | Solide als Fallback | Maximal kontrolliert, kein Self-Service nötig | Kein Selbstregistrierungsfluss, hoher Betriebsaufwand | Break-glass, Admin-/Testkonten citeturn27view1turn26search5 |
|
||||||
|
|
||||||
|
Wichtig für die Zielmodellierung: **Groups/Communities** sind im aktuellen Synapse-Kontext kein tragfähiges Onboarding-Ziel mehr. Die offizielle Synapse-Kommunikation beschreibt Groups/Communities als deprecated und ab Synapse 1.61 entfernt; Spaces sind der vorgesehene Ersatz. Wenn du also “Spaces, Groups, Rooms” als Zielbild denkst, sollte die reale Implementierung **Spaces + Rooms** heißen. citeturn17search0turn17search2
|
||||||
|
|
||||||
|
## MAS-Konfiguration und GitOps-Manifeste
|
||||||
|
|
||||||
|
ESS stellt laut offizieller Doku genau den von dir benötigten Mechanismus bereit: Zusätzliche MAS-Konfiguration wird unter `matrixAuthenticationService.additional` in YAML-Fragmente gelegt und in die finale MAS-Konfiguration gemerged. Dasselbe gilt für Synapse unter `synapse.additional` und für Element Web unter `elementWeb.additional`. citeturn1view2turn31view1
|
||||||
|
|
||||||
|
Der kleinste sinnvolle MAS-Block für invite-basierte Self-Registration sieht so aus. Die Felder `password_registration_enabled`, `registration_token_required` und `password_registration_email_required` sind offiziell dokumentiert; ESS dokumentiert zusätzlich explizit, dass `password_registration_email_required: false` **nur** in Kombination mit Restriktionen wie `registration_token_required: true` auf öffentlich föderierenden Deployments verantwortbar ist, weil die Instanz sonst missbraucht werden kann. citeturn2view4turn20view0turn1view2
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: ess-mas-values-secret
|
||||||
|
namespace: matrix
|
||||||
|
stringData:
|
||||||
|
values.yaml: |
|
||||||
|
matrixAuthenticationService:
|
||||||
|
additional:
|
||||||
|
10-account.yaml:
|
||||||
|
config: |
|
||||||
|
passwords:
|
||||||
|
enabled: true
|
||||||
|
minimum_complexity: 3
|
||||||
|
|
||||||
|
account:
|
||||||
|
password_registration_enabled: true
|
||||||
|
registration_token_required: true
|
||||||
|
password_registration_email_required: false
|
||||||
|
password_change_allowed: true
|
||||||
|
password_recovery_enabled: false
|
||||||
|
login_with_email_allowed: false
|
||||||
|
|
||||||
|
# Optional, falls du Recoveries / Verifizierung brauchst
|
||||||
|
email:
|
||||||
|
from: '"Matrix Auth" <no-reply@__DOMAIN__>'
|
||||||
|
reply_to: '"Support" <support@__DOMAIN__>'
|
||||||
|
transport: smtp
|
||||||
|
mode: starttls
|
||||||
|
hostname: __SMTP_HOST__
|
||||||
|
port: 587
|
||||||
|
username: __SMTP_USERNAME__
|
||||||
|
password: __SMTP_PASSWORD__
|
||||||
|
|
||||||
|
# Für halböffentliche Setups empfehlenswert
|
||||||
|
captcha:
|
||||||
|
service: cloudflare_turnstile
|
||||||
|
site_key: __TURNSTILE_SITE_KEY__
|
||||||
|
secret_key: __TURNSTILE_SECRET_KEY__
|
||||||
|
|
||||||
|
policy:
|
||||||
|
data:
|
||||||
|
registration:
|
||||||
|
banned_usernames:
|
||||||
|
literals: ["admin", "root", "support"]
|
||||||
|
emails:
|
||||||
|
allowed_addresses:
|
||||||
|
suffixes: ["@example.org"]
|
||||||
|
requester:
|
||||||
|
banned_ips:
|
||||||
|
- 10.0.0.0/8
|
||||||
|
- 192.168.0.0/16
|
||||||
|
|
||||||
|
rate_limiting:
|
||||||
|
registration:
|
||||||
|
burst: 2
|
||||||
|
per_second: 0.0003
|
||||||
|
login:
|
||||||
|
per_ip:
|
||||||
|
burst: 5
|
||||||
|
per_second: 0.02
|
||||||
|
per_account:
|
||||||
|
burst: 30
|
||||||
|
per_second: 0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Damit externe Tools Tokens anlegen können, muss die **MAS Admin API** aktiviert werden. Die offizielle MAS-Doku sagt ausdrücklich, dass `adminapi` nicht standardmäßig exponiert ist und in einen Listener aufgenommen werden muss; Zugriffe werden mit dem Scope `urn:mas:admin` geschützt. Für automatisierte Tools ist der dokumentierte Weg ein **OAuth-Client mit `client_credentials`**, dessen `client_id` in `policy.data.admin_clients` steht. citeturn20view1turn23view0turn23view3
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: ess-mas-admin-client
|
||||||
|
namespace: matrix
|
||||||
|
stringData:
|
||||||
|
admin-client.yaml: |
|
||||||
|
http:
|
||||||
|
listeners:
|
||||||
|
- name: web
|
||||||
|
resources:
|
||||||
|
- name: discovery
|
||||||
|
- name: human
|
||||||
|
- name: oauth
|
||||||
|
- name: compat
|
||||||
|
- name: graphql
|
||||||
|
playground: false
|
||||||
|
- name: assets
|
||||||
|
path: ./share/assets/
|
||||||
|
- name: adminapi
|
||||||
|
binds:
|
||||||
|
- address: "[::]:8080"
|
||||||
|
|
||||||
|
clients:
|
||||||
|
- client_id: 01JV0000000000000000000001
|
||||||
|
client_auth_method: client_secret_basic
|
||||||
|
client_secret: "__MAS_ADMIN_CLIENT_SECRET__"
|
||||||
|
|
||||||
|
policy:
|
||||||
|
data:
|
||||||
|
admin_clients:
|
||||||
|
- 01JV0000000000000000000001
|
||||||
|
```
|
||||||
|
|
||||||
|
Dieses Secret bindest du wiederum als weiteren `additional`-Eintrag ein. So vermeidest du Dateipfad-Annahmen im Container und hältst den Client-Secret-Wert SOPS-fähig. citeturn31view1turn20view1turn23view0
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: ess-mas-values-secret
|
||||||
|
namespace: matrix
|
||||||
|
stringData:
|
||||||
|
values.yaml: |
|
||||||
|
matrixAuthenticationService:
|
||||||
|
additional:
|
||||||
|
20-admin-client.yaml:
|
||||||
|
configSecret: ess-mas-admin-client
|
||||||
|
configSecretKey: admin-client.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Für FluxCD genügt ein klassisches `valuesFrom`-Muster. Das bildet dein bestehendes Repo-Schema mit ConfigMaps/Secrets gut ab und bleibt mit SOPS kompatibel. citeturn31view1turn1view2
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: matrix-stack
|
||||||
|
namespace: matrix
|
||||||
|
spec:
|
||||||
|
interval: 1h
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: matrix-stack
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: element-ess-oci
|
||||||
|
namespace: flux-system
|
||||||
|
valuesFrom:
|
||||||
|
- kind: ConfigMap
|
||||||
|
name: ess-synapse-custom
|
||||||
|
valuesKey: values.yaml
|
||||||
|
- kind: ConfigMap
|
||||||
|
name: ess-element-custom
|
||||||
|
valuesKey: values.yaml
|
||||||
|
- kind: Secret
|
||||||
|
name: ess-mas-values-secret
|
||||||
|
valuesKey: values.yaml
|
||||||
|
values:
|
||||||
|
serverName: "__SERVER_NAME__"
|
||||||
|
postgres:
|
||||||
|
enabled: true
|
||||||
|
synapse:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: "__SYNAPSE_HOST__"
|
||||||
|
matrixAuthenticationService:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: "__MAS_HOST__"
|
||||||
|
elementWeb:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: "__ELEMENT_HOST__"
|
||||||
|
matrixRTC:
|
||||||
|
enabled: true
|
||||||
|
ingress:
|
||||||
|
host: "__MRTC_HOST__"
|
||||||
|
```
|
||||||
|
|
||||||
|
Für das automatische Standard-Onboarding nimmst du Synapse `auto_join_rooms`. Die offizielle Synapse-Doku bestätigt: neue Benutzer werden automatisch zu den gelisteten Räumen hinzugefügt; **Space-Aliasse sind erlaubt**, weil Spaces Räume sind; **Spaces werden aber nicht automatisch erzeugt**, und für private/invite-only Auto-Join-Setups muss `auto_join_mxid_localpart` gesetzt sein, wobei dieser Benutzer in den betreffenden Räumen Mitglied sein und Einladungsrechte haben muss. citeturn16view0turn16view1turn16view2
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ess-synapse-custom
|
||||||
|
namespace: matrix
|
||||||
|
data:
|
||||||
|
values.yaml: |
|
||||||
|
synapse:
|
||||||
|
additional:
|
||||||
|
20-onboarding.yaml:
|
||||||
|
config: |
|
||||||
|
auto_join_rooms:
|
||||||
|
- "#welcome:__SERVER_NAME__"
|
||||||
|
- "#announcements:__SERVER_NAME__"
|
||||||
|
- "#community-space:__SERVER_NAME__"
|
||||||
|
|
||||||
|
autocreate_auto_join_rooms: false
|
||||||
|
auto_join_mxid_localpart: system
|
||||||
|
auto_join_rooms_for_guests: false
|
||||||
|
```
|
||||||
|
|
||||||
|
Für die User Experience kannst du Element Web mit einer eigenen Welcome-/Invite-Seite versehen. Offiziell unterstützt Element Web dafür `embedded_pages.welcome_url`, `login_for_welcome`, Branding-Parameter und – für native OIDC-Setups – OIDC-Client-Optionen. Für deinen Fall ist das vor allem nützlich, **weil die offizielle MAS-Dokumentation keinen stabil dokumentierten URL-Parameter zum Prefill eines Registration Tokens beschreibt**; die saubere Lösung ist daher oft eine eigene Landing-Page, die den Token erklärt oder temporär speichert und dann zum Registrierungsfluss führt. Diese Aussage ist eine Architektur-Inferenz aus den offiziellen Element- und MAS-Dokumenten. citeturn24search0turn20view1turn22view0
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ess-element-custom
|
||||||
|
namespace: matrix
|
||||||
|
data:
|
||||||
|
values.yaml: |
|
||||||
|
elementWeb:
|
||||||
|
additional:
|
||||||
|
config.json: |
|
||||||
|
{
|
||||||
|
"embedded_pages": {
|
||||||
|
"welcome_url": "https://__ELEMENT_HOST__/invite/index.html",
|
||||||
|
"login_for_welcome": false
|
||||||
|
},
|
||||||
|
"branding": {
|
||||||
|
"auth_header_logo_url": "https://__ELEMENT_HOST__/assets/logo.svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Ein wichtiger Betriebs-Hinweis: Es gibt aktuell ein **offenes GitHub-Issue** im ESS-Helm-Repository, das meldet, dass `matrixAuthenticationService.additional.*` in bestimmten Konstellationen ignoriert werden könne. Das ist kein offizieller Release-Hinweis, aber als Failure-Mode ernst zu nehmen. Deshalb solltest du nach jeder Änderung das **gerenderte MAS-ConfigFile im Pod** prüfen, bevor du mit echten Einladungen arbeitest. citeturn38view0turn31view1
|
||||||
|
|
||||||
|
## Einladungsworkflow und Provisionierung
|
||||||
|
|
||||||
|
Der saubere GitOps-Ablauf ist in der Praxis fünfstufig. Zuerst legst du **statische Konfiguration** in Git ab: MAS-Settings, SMTP, Admin-Client, Synapse Auto-Join. Danach reconciled Flux diese Ressourcen in den Cluster. Anschließend erzeugt Ansible oder ein Shell-Skript **on demand** ein kurzlebiges Registration Token über die MAS Admin API. Dieses Token wird per E-Mail verschickt – entweder als Link zu deiner eigenen Invite-Landing-Page oder als Nachricht mit Token + Registrierungsanweisung. Beim ersten erfolgreichen Abschluss der Registrierung provisioniert MAS den Account in Synapse; Synapse zieht dann `auto_join_rooms`. Wenn du danach noch gezielt Spaces/Räume abhängig von Abteilung, Rolle oder Domäne vergeben willst, übernimmt das ein Provisioner oder ein Synapse-Modul. citeturn20view1turn12view0turn16view0turn34view0
|
||||||
|
|
||||||
|
Für die **MAS Admin API** ist der dokumentierte Automationspfad `client_credentials`. Die MAS-Doku nennt dafür explizit statische Clients + `policy.data.admin_clients`. Das Access-Token kannst du discovery-basiert holen, damit du keine Token-Endpoint-Pfade hart codierst. citeturn20view1turn22view0turn23view0
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MAS_ISSUER="https://account.__DOMAIN__/"
|
||||||
|
CLIENT_ID="01JV0000000000000000000001"
|
||||||
|
CLIENT_SECRET="${MAS_ADMIN_CLIENT_SECRET}"
|
||||||
|
|
||||||
|
TOKEN_ENDPOINT="$(
|
||||||
|
curl -fsSL "${MAS_ISSUER}.well-known/openid-configuration" \
|
||||||
|
| jq -r '.token_endpoint'
|
||||||
|
)"
|
||||||
|
|
||||||
|
ACCESS_TOKEN="$(
|
||||||
|
curl -fsSL -u "${CLIENT_ID}:${CLIENT_SECRET}" \
|
||||||
|
-H 'Content-Type: application/x-www-form-urlencoded' \
|
||||||
|
-d 'grant_type=client_credentials' \
|
||||||
|
-d 'scope=urn:mas:admin' \
|
||||||
|
"${TOKEN_ENDPOINT}" \
|
||||||
|
| jq -r '.access_token'
|
||||||
|
)"
|
||||||
|
|
||||||
|
curl -fsSL -X POST "https://account.__DOMAIN__/api/admin/v1/user-registration-tokens" \
|
||||||
|
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{
|
||||||
|
"usage_limit": 1,
|
||||||
|
"expires_at": "2026-05-01T12:00:00Z"
|
||||||
|
}' | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
Die MAS-OpenAPI-Spezifikation dokumentiert für Registration Tokens genau die Felder, die du dafür brauchst: `token` optional, `usage_limit`, `expires_at`, dazu die Verwaltungsendpunkte zum **Listen**, **Updaten**, **Revoken** und **Unrevoken** unter `/api/admin/v1/user-registration-tokens`. “Valid” bedeutet laut Spec: nicht abgelaufen, nicht widerrufen und Usage-Limit nicht ausgeschöpft. Für Invite-Flows solltest du in der Regel **`usage_limit: 1` und kurze Expiry-Zeiten** verwenden. citeturn12view0turn13view0turn37view0turn37view1turn37view2
|
||||||
|
|
||||||
|
Beispiel für Rotation bzw. Widerruf eines ungenutzten Tokens:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TOKEN_ID="01JVABCDEF..."
|
||||||
|
curl -fsSL -X POST "https://account.__DOMAIN__/api/admin/v1/user-registration-tokens/${TOKEN_ID}/revoke" \
|
||||||
|
-H "Authorization: Bearer ${ACCESS_TOKEN}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Wenn du Token-Limits oder die Ablaufzeit nachträglich anpassen willst, ist laut MAS-Admin-Spec `PUT /api/admin/v1/user-registration-tokens/{id}` der vorgesehene Weg. citeturn13view0turn11view0
|
||||||
|
|
||||||
|
In Ansible lässt sich derselbe Flow sehr gut abbilden. Hier ein minimales Beispiel mit Discovery, Token-Erzeugung und Mailversand. Der SMTP-Provider ist bewusst als Platzhalter gelassen, weil du ihn nicht spezifiziert hast. Die Speicherung des erzeugten Registration-Tokens in Git ist **optional**; ich würde standardmäßig nur **Token-ID, Empfänger, Ablaufzeit und Versandzeitpunkt** als Audit speichern, nicht das Secret selbst. citeturn20view1turn12view0turn3view1turn2view5
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Discover MAS token endpoint
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "https://account.__DOMAIN__/.well-known/openid-configuration"
|
||||||
|
return_content: true
|
||||||
|
register: oidc_discovery
|
||||||
|
|
||||||
|
- name: Get MAS admin access token
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "{{ oidc_discovery.json.token_endpoint }}"
|
||||||
|
method: POST
|
||||||
|
user: "{{ mas_admin_client_id }}"
|
||||||
|
password: "{{ mas_admin_client_secret }}"
|
||||||
|
force_basic_auth: true
|
||||||
|
body_format: form-urlencoded
|
||||||
|
body:
|
||||||
|
grant_type: client_credentials
|
||||||
|
scope: urn:mas:admin
|
||||||
|
return_content: true
|
||||||
|
register: mas_oauth
|
||||||
|
|
||||||
|
- name: Create single-use registration token
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "https://account.__DOMAIN__/api/admin/v1/user-registration-tokens"
|
||||||
|
method: POST
|
||||||
|
headers:
|
||||||
|
Authorization: "Bearer {{ mas_oauth.json.access_token }}"
|
||||||
|
body_format: json
|
||||||
|
body:
|
||||||
|
usage_limit: 1
|
||||||
|
expires_at: "{{ invite_expires_at }}"
|
||||||
|
return_content: true
|
||||||
|
register: mas_invite
|
||||||
|
|
||||||
|
- name: Build invite URL
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
invite_url: "https://__ELEMENT_HOST__/invite/?token={{ mas_invite.json.data.attributes.token | urlencode }}"
|
||||||
|
|
||||||
|
- name: Send invitation email
|
||||||
|
community.general.mail:
|
||||||
|
host: "__SMTP_HOST__"
|
||||||
|
port: 587
|
||||||
|
secure: starttls
|
||||||
|
username: "__SMTP_USER__"
|
||||||
|
password: "__SMTP_PASSWORD__"
|
||||||
|
to: "{{ invitee_email }}"
|
||||||
|
from: "no-reply@__DOMAIN__"
|
||||||
|
subject: "Deine Matrix-Einladung"
|
||||||
|
body: |
|
||||||
|
Hallo,
|
||||||
|
|
||||||
|
hier ist deine Einladung für Matrix.
|
||||||
|
Einladung: {{ invite_url }}
|
||||||
|
|
||||||
|
Das Token ist einmalig nutzbar und gültig bis {{ invite_expires_at }}.
|
||||||
|
```
|
||||||
|
|
||||||
|
Für die **automatische Zuweisung** zu Spaces/Räumen nach erster Anmeldung gibt es drei robuste Muster:
|
||||||
|
|
||||||
|
Erstens der Standardpfad über `auto_join_rooms`: ideal für **alle** neuen Benutzer, z. B. `#welcome`, `#announcements` und ein Haupt-Space. Das ist die einfachste und offizielle Lösung. Zweitens ein **Post-Registration-Provisioner**, der den Benutzer zusätzlich in weitere Räume einlädt oder joined. Dafür ist der offizielle Synapse-Admin-Endpunkt `POST /_synapse/admin/v1/join/<room_id_or_alias>` gedacht. Drittens ein **Synapse-Modul**, das `on_user_registration` oder `on_user_login` implementiert. Die Primärdoku beschreibt genau diese Callback-Punkte; seit Synapse 1.135 müssen Module allerdings worker-safe sein, weil `on_user_registration` auch auf Workern laufen kann. citeturn16view0turn27view0turn34view0turn35view0
|
||||||
|
|
||||||
|
Ein Provisioner gegen die Synapse Admin API kann so aussehen. Dabei setze ich voraus, dass du bereits einen **user-bound** Synapse-Admin-Token hast; dafür verweist die offizielle MAS-Doku auf den Device-Code-Flow mit Synapse-Admin-Scopes. Dasselbe Dokument zeigt auch, wie man kombinierte MAS-/Synapse-Admin-Tokens interaktiv anfordern kann. citeturn27view0turn32search1turn32search0
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SYNAPSE_BASE="https://matrix.__DOMAIN__"
|
||||||
|
SYNAPSE_ADMIN_TOKEN="${SYNAPSE_ADMIN_TOKEN}"
|
||||||
|
USER_ID="$1"
|
||||||
|
|
||||||
|
join_room() {
|
||||||
|
local alias="$1"
|
||||||
|
curl -fsSL -X POST \
|
||||||
|
-H "Authorization: Bearer ${SYNAPSE_ADMIN_TOKEN}" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
"${SYNAPSE_BASE}/_synapse/admin/v1/join/${alias}" \
|
||||||
|
-d "{\"user_id\":\"${USER_ID}\"}" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
join_room "#community-space:__SERVER_NAME__"
|
||||||
|
join_room "#announcements:__SERVER_NAME__"
|
||||||
|
join_room "#team-general:__SERVER_NAME__"
|
||||||
|
```
|
||||||
|
|
||||||
|
Wichtig ist hier die Abgrenzung zu “Claim Mappings”: Die offizielle MAS-OIDC-Doku beschreibt `claims_imports` für **`localpart`**, **`displayname`**, **`email`** und **`account_name`**. Daraus folgt: Claim-Mappings sind nützlich, wenn du später doch einen Upstream-OIDC-Provider ergänzen willst, aber sie lösen **nicht** die Mitgliedschaft in Spaces/Räumen. Für deinen Authentik-freien Invite-Flow ist das korrekte Modell also **Token + Synapse-Onboarding**, nicht “Claims → Rooms”. citeturn21search1turn9search4
|
||||||
|
|
||||||
|
## Sicherheit und Betriebsmodell
|
||||||
|
|
||||||
|
Die sicherste Konfiguration für dein Szenario ist nicht “offene Registrierung mit etwas Deko”, sondern **echte Invite-only-Registrierung**. Das bedeutet konkret: `password_registration_enabled: true`, `registration_token_required: true` und nur dann `password_registration_email_required: false`, wenn du bewusst auf Token-Schutz, kurze Laufzeiten, Single-Use und gute Missbrauchsbarrieren setzt. Genau davor warnt die ESS-Doku ausdrücklich: Ein öffentlich föderierender Server ohne Mailpflicht **und** ohne starke Restriktionen wird missbraucht. citeturn2view4turn20view0turn1view2
|
||||||
|
|
||||||
|
Ich würde die Sicherheitsprofile so priorisieren:
|
||||||
|
|
||||||
|
| Profil | Empfohlene Settings | Wann sinnvoll | Kommentar |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Striktes Invite-only | `password_registration_enabled: true`, `registration_token_required: true`, `password_registration_email_required: false`, `usage_limit: 1`, kurze Expiry | Kleine Community, kuratierte Benutzerbasis | Beste Mischung aus UX und Missbrauchsschutz citeturn2view4turn12view0turn37view2 |
|
||||||
|
| Invite-only mit Recovery | Wie oben, aber `password_recovery_enabled: true` und SMTP voll konfiguriert | Wenn Nutzer Self-Service-Passwort-Reset brauchen | Erhöht Komfort, verlangt sauberen Mailbetrieb citeturn2view4turn2view5 |
|
||||||
|
| Halböffentlich | Tokenpflicht + CAPTCHA + E-Mail-Allowlist + restriktivere Rate-Limits | Wenn Einladungen wiederverwendbar oder breiter verteilt werden | Mehr Schutz gegen Bot-/Spam-Missbrauch citeturn3view2turn20view0turn3view1 |
|
||||||
|
|
||||||
|
Zu den wichtigsten Härtungsmaßnahmen gehören: **Single-Use (`usage_limit: 1`)**, **kurze Gültigkeit**, **Rate Limits für Registrierungen**, **optional CAPTCHA**, **optional Domain-Allowlist für E-Mails**, **Banned IP/User-Agent-Regeln** und ein **interner oder streng geschützter MAS-Admin-API-Zugang**. MAS dokumentiert all diese Stellhebel explizit: `policy.data.registration.*`, `emails.allowed_addresses`, `requester.banned_ips`, CAPTCHA-Provider und `rate_limiting.registration`. citeturn20view0turn3view1turn3view2turn2view5
|
||||||
|
|
||||||
|
Für die Raum-/Space-Seite gilt zusätzlich: Halte sensible Onboarding-Räume **invite-only** und vermische “öffentlich sichtbare Discovery” nicht mit einem privaten Invite-Modell. Die Matrix-/Synapse-Dokumentation empfiehlt bei privaten Setups ausdrücklich, die Sichtbarkeit öffentlicher Räume restriktiv zu halten; Synapse hat die Standardregeln für Room-Directory-Publikation in neueren Versionen auch bewusst verschärft. citeturn17search6turn35view0
|
||||||
|
|
||||||
|
Ein subtiler, aber wichtiger Punkt ist die Trennung von **MAS Admin** und **Synapse Admin**. Offiziell ist `urn:mas:admin` für automatisierte `client_credentials`-Tools dokumentiert. Für `urn:synapse:admin:*` beschreibt die Scope-Referenz dagegen ein benutzergebundenes Modell; außerdem braucht Synapse-Admin zusätzlich die Matrix-API-Scopes. Daraus folgt als belastbare Betriebsregel: **Reine Maschinenautomation sollte primär MAS Admin API nutzen; Synapse-Admin-Aktionen entweder über Auto-Join, über ein Synapse-Modul oder über einen echten Service-User mit benutzergebundenem Admin-Token**. citeturn20view1turn32search0turn32search1
|
||||||
|
|
||||||
|
## Tests, Rollout und Recovery
|
||||||
|
|
||||||
|
Der Rollout sollte nicht mit echten Einladungen beginnen, sondern mit einem **vollständigen Dry-Run auf Staging oder einem Testkonto**. Zuerst reconcile-st du Flux, dann prüfst du das HelmRelease und die gerenderte MAS-Konfiguration. Danach testest du die MAS Admin API, erzeugst ein kurzes Einmal-Token, registrierst einen neuen Testnutzer, überprüfst `times_used`/`valid`, kontrollierst die Raum-/Space-Mitgliedschaften und widerrufst übrige Tokens. Damit deckst du sowohl die ESS-/MAS-Seite als auch die Synapse-Onboarding-Seite einmal komplett ab. citeturn20view1turn12view0turn16view0turn27view0
|
||||||
|
|
||||||
|
Die fachliche Checkliste dafür ist kurz, aber strikt:
|
||||||
|
|
||||||
|
- **Konfiguration vorhanden:** `matrixAuthenticationService.additional` und `synapse.additional` sind im gerenderten Config-Output sichtbar. Wegen des offenen ESS-Issues zu `additional.*` solltest du das aktiv prüfen. citeturn31view1turn38view0
|
||||||
|
- **MAS Admin API erreichbar:** `/api/spec.json` bzw. das Anlegen eines Tokens funktioniert mit `urn:mas:admin`. citeturn20view1turn10view0
|
||||||
|
- **Token-Lebenszyklus korrekt:** neues Token erscheint als `valid`, nach Nutzung steigt `times_used`, bei `usage_limit: 1` ist es anschließend nicht mehr gültig. citeturn12view0turn37view2
|
||||||
|
- **Onboarding korrekt:** Testnutzer landet im Haupt-Space, in Welcome/Announcements und – falls aktiviert – in weiteren Zielräumen. citeturn16view0turn27view0
|
||||||
|
- **Missbrauchsschutz greift:** Ablaufzeit, CAPTCHA, Rate-Limits und Policy-Regeln sind aktiv. citeturn3view1turn3view2turn20view0
|
||||||
|
|
||||||
|
Die wichtigsten Failure Modes und ihre Recovery-Schritte sind diese:
|
||||||
|
|
||||||
|
| Symptom | Wahrscheinliche Ursache | Recovery |
|
||||||
|
|---|---|---|
|
||||||
|
| Registrierung fordert trotzdem E-Mail-Verifikation | `password_registration_email_required` ist noch `true` oder falsches MAS-Configfile aktiv | Gerendertes MAS-Configfile prüfen, Werte korrigieren, neu deployen citeturn2view4turn1view2turn38view0 |
|
||||||
|
| `403` bei Token-Erzeugung | OAuth-Client nicht in `policy.data.admin_clients` oder falscher Scope | Client-/Policy-Fragment korrigieren, neuen Access Token holen citeturn20view1turn23view3 |
|
||||||
|
| `404` auf `/api/admin/v1/...` | `adminapi` nicht in `http.listeners.resources` aktiviert | Listener-Block korrigieren und Redeploy citeturn20view1 |
|
||||||
|
| User landet nicht im Space | Space existiert nicht, Space wurde nicht separat angelegt, oder `auto_join_mxid_localpart`-User kann nicht einladen | Space vorab anlegen, `system`-User joinen lassen, Rechte prüfen; Spaces werden nicht automatisch erstellt citeturn16view0turn16view1turn16view2 |
|
||||||
|
| Feingranulare Raumzuweisung klappt nicht | Du versuchst Membership über Claim-Mapping zu lösen | Membership über Auto-Join, Provisioner oder Synapse-Modul abbilden citeturn21search1turn34view0 |
|
||||||
|
| “Groups” lassen sich nicht mehr sinnvoll zuweisen | Groups/Communities sind im aktuellen Synapse-Modell entfernt | Auf Spaces + Rooms umstellen citeturn17search0turn17search2 |
|
||||||
|
|
||||||
|
Wenn ein Invite-Token versehentlich verschickt wurde, ist der saubere Recovery-Schritt **nicht** das HelmRelease zu verändern, sondern das Token per MAS Admin API zu **revoken** und bei Bedarf ein neues zu erzeugen. Wenn ein Benutzer zwar registriert wurde, aber Raumzuweisungen fehlen, ist die schnellste operative Korrektur ein nachgelagerter Join über den Synapse-Admin-Endpunkt. Wenn ein Synapse-Modul dafür verantwortlich ist, beachte die Worker-Eigenschaft von `on_user_registration`. citeturn13view0turn27view0turn35view0
|
||||||
|
|
||||||
|
## Quellenbasis und offene Punkte
|
||||||
|
|
||||||
|
Die belastbarsten Primärquellen für dieses Design sind die offiziellen Dokumentationen zu ESS, MAS, Synapse, Element Web und LiveKit. Für den Vergleichspfad “Authentik Invitations” ist die offizielle Authentik-Doku hinzugezogen worden.
|
||||||
|
|
||||||
|
Die Priorisierung war dabei:
|
||||||
|
|
||||||
|
- ESS Advanced-Doku zur Einbindung zusätzlicher Konfigurationsdateien für MAS, Synapse, Element Web und MatrixRTC. citeturn1view2
|
||||||
|
- ESS Chart-Values zur Bestätigung, dass `matrixAuthenticationService.additional`/`synapse.additional`/`elementWeb.additional` offizielle Wertepfade sind. citeturn31view1turn31view4
|
||||||
|
- MAS-Konfigurationsreferenz für `account.*`, `captcha`, `policy`, `rate_limiting`, `email`, `clients`, `admin_clients` und HTTP-Listener. citeturn2view4turn20view0turn22view0turn23view0
|
||||||
|
- MAS Admin API und OpenAPI-Schema für Token-Erzeugung, Update, Revoke, Validitätsbegriff und Automationsmodell. citeturn20view1turn12view0turn13view0turn37view1turn37view2
|
||||||
|
- MAS Scope- und Access-Token-Doku für den Unterschied zwischen `urn:mas:admin` und benutzergebundenem Synapse-Admin-Zugriff. citeturn32search0turn32search1
|
||||||
|
- Synapse-Konfigurationsmanual für `auto_join_rooms`, Space-Aliasse, `autocreate_auto_join_rooms` und `auto_join_mxid_localpart`. citeturn16view0turn16view1turn16view2
|
||||||
|
- Synapse-Admin- und Modul-Doku für Raumzuweisung per API und Callback-Punkte `on_user_registration` / `on_user_login`. citeturn27view0turn34view0turn35view0
|
||||||
|
- Element-Web-Konfiguration für Welcome-/Branding-/OIDC-nahe UX-Optionen. citeturn24search0
|
||||||
|
- LiveKit-/Element-Call-Doku als optionale, vom Registrierungsfluss getrennte RTC-Schicht. citeturn25search0turn25search13
|
||||||
|
- Authentik-Invitationsdoku nur für den Vergleich innerhalb der Optionen-Tabelle. citeturn36search0turn36search1
|
||||||
|
|
||||||
|
Offen beziehungsweise bewusst konservativ behandelt bleiben drei Punkte. Erstens beschreibt die offizielle MAS-Dokumentation nach dem hier ausgewerteten Stand **keinen stabil dokumentierten Invite-Link-Parameter**, mit dem ein Registration Token sicher per URL in die MAS-UI vorbefüllt wird; deshalb empfehle ich eine eigene Landing-Page oder Token-Übermittlung im Mailtext. Zweitens ist **client_credentials** sauber für die **MAS Admin API** dokumentiert, nicht aber als Standardmuster für **Synapse-Admin-Automation**; für Synapse-Onboarding ist deshalb `auto_join_rooms` oder ein user-/modulbasierter Pfad robuster. Drittens gibt es aktuell ein offenes ESS-Helm-Issue zu `matrixAuthenticationService.additional.*`; deshalb solltest du das gerenderte MAS-Configfile im Deployment immer verifizieren, bevor du produktive Einladungen versendest. citeturn20view1turn32search0turn38view0
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user