sorb tested a group call after the restart and it works. That proves what curl could not: the full OpenID token check through /_matrix/federation/v1/openid/userinfo still completes with federation closed, so the whitelist genuinely does not reach that endpoint. It is also where option C finally died. Blocking /_matrix/federation at the edge would have removed exactly this path, and nothing before the call would have shown it.
145 lines
6.9 KiB
Markdown
145 lines
6.9 KiB
Markdown
---
|
|
type: issue
|
|
id: "0060"
|
|
status: done
|
|
created: 2026-07-28
|
|
milestone: M1
|
|
priority: medium
|
|
area: security
|
|
projekt: gitops
|
|
gitlab_iid: "17"
|
|
related: []
|
|
---
|
|
# Federation allowlist or closed federation decision
|
|
|
|
> Adoptiert aus [gitops#17](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/17) (2026-08-18, ADR-0019). Kommentare und Verlauf bleiben dort; kanonisch ist ab jetzt diese Datei.
|
|
|
|
Decide: open federation with all public Matrix servers (current default, larger attack surface) vs. an explicit `federation_domain_whitelist`, vs. fully closed federation (`allow_public_rooms_without_join_rules: false`). Config lives in `apps/production/custom-configs/synapse-values.yaml`.
|
|
|
|
---
|
|
*Migriert aus Gitea `sorb/axion1337.chat-gitops#17` — dort erstellt am 2026-07-28 von sorb.*
|
|
<!-- gitea-migration: sorb/axion1337.chat-gitops#17 -->
|
|
|
|
## Entscheidungsgrundlage 2026-08-19 — gemessen statt geschätzt
|
|
|
|
Die Frage war seit dem 2026-07-28 offen, weil niemand wusste, was eine Schließung
|
|
kosten würde. Jetzt ist es beziffert.
|
|
|
|
**Föderation ist offen und öffentlich erreichbar.** In `synapse-values.yaml` steht zu
|
|
Föderation **nichts** — es gelten die Synapse-Vorgaben. Von außen gemessen:
|
|
|
|
```
|
|
https://matrix.axion1337.chat/_matrix/federation/v1/version -> HTTP 200
|
|
https://matrix.axion1337.chat/_matrix/key/v2/server -> HTTP 200
|
|
```
|
|
|
|
Port 8448 ist zwar zu, das ändert nichts: Die Delegation
|
|
(`/.well-known/matrix/server` → `matrix.axion1337.chat:443`) führt die Föderation über
|
|
den regulären HTTPS-Port, und der ist offen.
|
|
|
|
**Benutzt wurde sie noch nie.** Aus der Synapse-Datenbank, über die gesamte Betriebszeit
|
|
(Erstkonto 2026-04-21):
|
|
|
|
| | |
|
|
|---|---|
|
|
| Zielserver in `destinations` | **0** |
|
|
| davon je erfolgreich kontaktiert | **0** |
|
|
| fremde Nutzer in unseren Räumen | **0** |
|
|
| Räume mit fremder Beteiligung | **0** |
|
|
| eigene Räume | 31 |
|
|
|
|
Nicht „wenig genutzt" — **null**, in vier Monaten. Damit kostet eine Schließung heute
|
|
nichts Messbares; sie nimmt nur eine Möglichkeit weg, die niemand wahrgenommen hat.
|
|
|
|
**Was dagegen bezahlt wird:** Die Föderations-Schnittstelle ist die größte
|
|
fremdzugewandte Angriffsfläche, die Synapse hat, und historisch die, in der seine CVEs
|
|
sitzen. Jeder Matrix-Server der Welt darf derzeit Beitritts- und Ereignisverkehr
|
|
versuchen.
|
|
|
|
### Optionen mit ihren Folgen
|
|
|
|
**A — offen lassen (Ist-Zustand).** Kein Aufwand. Wir bezahlen dauerhaft
|
|
Angriffsfläche für eine Fähigkeit mit null nachgewiesenem Bedarf.
|
|
|
|
**B — `federation_domain_whitelist` mit leerer Liste.** Föderation nur mit
|
|
ausdrücklich genannten Servern; leer heißt: mit keinem. Eine Zeile Konfiguration,
|
|
über GitOps versioniert, in Minuten rückgängig durch Eintragen einer Domain.
|
|
⚠️ **Was es NICHT tut:** Die Endpunkte antworten weiterhin (`key/v2/server`,
|
|
`federation/v1/version`) — der Server ist also nicht unsichtbar, nur unbeteiligt.
|
|
|
|
**C — Föderations-Listener ganz abschalten.** Kleinste Fläche, aber Eingriff in das
|
|
ESS-Chart und schwerer zurückzudrehen.
|
|
|
|
**Empfehlung: B.** Sie kostet heute nichts, ist eine Zeile, ist versioniert und hält die
|
|
Tür offen, ohne Miete dafür zu zahlen. C lohnt erst, wenn feststeht, dass Föderation
|
|
dauerhaft unerwünscht ist — dann als eigene Entscheidung mit ADR.
|
|
|
|
**Getrennt davon** nennt das Issue `allow_public_rooms_without_join_rules`: Das steuert
|
|
nur, ob das Raumverzeichnis über Föderation sichtbar ist, und ist unabhängig von der
|
|
Grundsatzfrage.
|
|
|
|
**Entscheidung sorb steht aus.**
|
|
|
|
## Entscheidung und Umsetzung 2026-08-19
|
|
|
|
**sorb: erst C, dann C verworfen — B umgesetzt.** Beim Bauen von C zeigte sich, dass
|
|
ein Pfad-Block die Gruppen-Calls zerstört hätte: `lk-jwt-service` prüft OpenID-Tokens
|
|
über `/_matrix/federation/v1/openid/userinfo` und ruft ihn über den **öffentlichen**
|
|
Namen auf (keine `hostAliases`, `dnsPolicy: ClusterFirst`), also über Traefik. Ein
|
|
Block auf `/_matrix/federation/` hätte denselben Ausfall erzeugt wie der gelöschte
|
|
`mrtc`-Record. Festgehalten als [ADR-0021](../adr/0021-foederation-geschlossen.md),
|
|
inklusive der Begründung, warum C nicht nachträglich „noch schnell" nachgeholt werden
|
|
sollte.
|
|
|
|
`federation_domain_whitelist: []` steht in
|
|
`gitops:apps/production/custom-configs/synapse-values.yaml` (Commit `3935f35`).
|
|
|
|
**Zwei Fallen beim Umsetzen, beide vor dem Ausrollen bemerkt:**
|
|
|
|
1. Der erste Einschub **zerschnitt den `auto_join`-Block** — `auto_join_rooms_for_guests`
|
|
landete unter `federation`. Nach dem Zusammenführen der Fragmente funktional
|
|
identisch, zu lesen falsch; korrigiert, der Diff ist jetzt 20 Zeilen Zugewinn und
|
|
nichts Verschobenes.
|
|
2. **Flux hat angewandt, Synapse lief weiter mit der alten Konfiguration.** Die
|
|
ConfigMap trug die Zeile, der laufende Pod nicht — er stammte vom 2026-08-01. Die
|
|
Konfiguration wird beim Pod-Start gerendert; ohne Neustart ist die Änderung
|
|
wirkungslos. Dieselbe Klasse wie #0044. Neustart per
|
|
`rollout restart statefulset/matrix-stack-synapse-main` angestoßen.
|
|
|
|
**Zur Hetzner-Port-Sperre:** Sie kann diese Trennung nicht leisten. 8448 ist bereits zu,
|
|
und die Delegation führt die Föderation über **443** — denselben Port wie alle Clients.
|
|
Die Synapse-Konfiguration ist die einzige Stelle, an der Föderation und Client-Verkehr
|
|
überhaupt trennbar sind.
|
|
|
|
### Abnahme nach dem Neustart (2026-08-19, Synapse-Start 11:13 UTC)
|
|
|
|
| Prüfung | Ergebnis |
|
|
|---|---|
|
|
| `federation_domain_whitelist: []` **im laufenden Prozess** (nicht nur in der ConfigMap) | ✅ vorhanden |
|
|
| `/_matrix/federation/v1/openid/userinfo` — die Element-Call-Abhängigkeit | ✅ HTTP 401 (bedient, verlangt Token) |
|
|
| `/_matrix/client/versions` — Client-Verkehr | ✅ HTTP 200 |
|
|
| `/_matrix/federation/v1/version` | HTTP 200 — **erwartet** |
|
|
|
|
Der letzte Punkt ist kein Mangel, sondern die bewusste Grenze von Option B: Die
|
|
Endpunkte antworten weiterhin, der Server ist **unbeteiligt, nicht unsichtbar**. Was
|
|
sich geändert hat, ist nicht die Sichtbarkeit, sondern dass Synapse mit keinem fremden
|
|
Server mehr Ereignisse austauscht.
|
|
|
|
**Noch offen: die Abnahme im echten Gruppen-Call.** `curl` belegt, dass der
|
|
OpenID-Endpunkt antwortet — nicht, dass die vollständige Token-Prüfung durchläuft. Für
|
|
Änderungen im Call-Pfad gilt hier die Regel aus #0054: Abnahme im echten Call ist
|
|
Rollout-Voraussetzung, nicht Nacharbeit.
|
|
|
|
### Call-Abnahme bestanden (sorb, 2026-08-19)
|
|
|
|
Gruppen-Call nach dem Synapse-Neustart getestet: **läuft**. Damit ist belegt, was
|
|
`curl` nicht belegen konnte — die vollständige OpenID-Token-Prüfung über
|
|
`/_matrix/federation/v1/openid/userinfo` durchläuft mit geschlossener Föderation
|
|
unverändert. Die Whitelist greift dort tatsächlich nicht.
|
|
|
|
Das ist der Punkt, an dem C endgültig gestorben ist: Genau dieser Pfad hätte bei einem
|
|
Block auf `/_matrix/federation/` gefehlt, und der Fehler wäre erst im Call aufgefallen.
|
|
|
|
**Issue erledigt.** Entscheidung, Begründung und die verworfene Alternative stehen in
|
|
[ADR-0021](../adr/0021-foederation-geschlossen.md).
|