Files
management/decisions/0011-enrollment-localpart-kollision-verweigern.md
T
Thore Cimbal dbc309dfd6 docs(adr): 0011 - reject localpart collisions in provisioning
Records on_conflict: fail as standing policy (identity provisioning never links
a new upstream identity to an existing local account), the residual prompt-stage
uniqueness check, and the SOPS-secret-needs-restart rule. Decided by sorb.
2026-08-11 12:00:00 +00:00

3.4 KiB

0011 — Provisionierung verweigert Localpart-Kollisionen, statt an bestehende Konten zu verknüpfen

Status: akzeptiert · Datum: 2026-08-11 · Entscheider: sorb

Kontext

Der MAS-Upstream-Provider für Authentik stand auf claims_imports.localpart.on_conflict: add. MAS-Semantik: Kollidiert der aus dem Authentik-Claim abgeleitete Localpart mit einem bestehenden Matrix-Konto, verknüpft MAS die neue Upstream-Identität mit diesem Konto — ohne Abbruch, ohne Warnung. Authentiks eigene Benutzernamen-Eindeutigkeit fängt das nicht ab: sie gilt nur innerhalb von Authentik und ist case-sensitive (boje neben Boje ging live durch). Folge: Ein Inhaber eines Einladungstokens konnte einen (auch nur in der Schreibweise abweichenden) Namen eines bestehenden Kontos registrieren und würde beim ersten Login in dessen Konto verknüpft — inklusive Dienstkonten ohne Upstream-Link (draupnir, alerts, maintenance-notify). Das ist ein Kontoübernahme-Vektor, entdeckt am 2026-08-11 beim Anlegen eines Testkontos (gitops#61).

Entscheidung

Identitäts-Provisionierung verknüpft eine neue Upstream-Identität niemals mit einem bereits bestehenden lokalen Konto. Konkret: on_conflict: fail im claims_imports.localpart-Block des MAS-Upstream-Providers (gitops/apps/production/custom-configs/mas-secret.yaml). Ein kollidierender Localpart bricht die Provisionierung ab. Dies ist ab jetzt stehende Regel, nicht nur der aktuelle Wert — jede künftige Änderung an diesem Verhalten braucht ein ablösendes ADR.

Konsequenzen

  • Besser: Der Übernahme-Weg ist geschlossen. Bestehende Konten (besonders die ohne Upstream-Link) können nicht mehr durch eine kollidierende Neuregistrierung gekapert werden. Bestehende, korrekte Verknüpfungen bleiben unberührt.
  • In Kauf genommen: Ein Nutzer, der einen bereits vergebenen Namen wählt, erhält die Fehlermeldung erst beim Login (wenn MAS provisioniert), nicht schon bei der Registrierung in Authentik. Das ist eine schlechtere UX, aber kein Sicherheitsproblem.
  • Jetzt Pflicht:
    • Als offene Härtung eine case-insensitive Eindeutigkeitsprüfung im matrix-invitation-Prompt-Stage, damit die Kollision schon bei der Registrierung sichtbar wird (verfolgt in gitops#61).
    • Nach jeder Änderung an einem SOPS-verwalteten Values-Secret den konsumierenden Dienst per rollout restart neu ausrollen und verifizieren, dass der Pod jünger als die Änderung ist. Beim Ausrollen dieses Fixes lief MAS noch mit der alten Config im Speicher, obwohl das Secret bereits fail zeigte — „committet" ≠ „deployed" ≠ „aktiv" (MAS liest Config nur beim Start).

Verworfene Alternativen

  • on_conflict: add belassen und allein auf Authentiks Eindeutigkeit vertrauen — verworfen: die greift nur innerhalb Authentiks und case-sensitive, deckt Kollisionen mit vorbestehenden Matrix-Konten also nicht ab.
  • Nur den Prompt-Stage-Check bauen, MAS auf add lassen — verworfen: der Client-seitige Check ist umgehbar (direkter Flow-Aufruf), der MAS-seitige Abbruch ist die eigentliche Sicherheitsgrenze. Der Prompt-Check ist die UX-Ergänzung, nicht der Schutz.
  • Betroffene Dienstkonten einfach mit Upstream-Links versehen — verworfen: behandelt nur das Symptom für heute bekannte Konten, nicht den Mechanismus.