ADR-0012 made docs/issues/ canonical for the management scope only and left gitops, ThreadNet-Web and threadnet-call on GitLab "until the component adopts". That split produced exactly what it invited: two numbering worlds where management#20 and gitops#20 are different issues, drift nobody had to answer for (gitops#61 carried no milestone since 2026-08-11), and component backlogs that host sessions without lab access cannot read at all. The 46 open component issues are now files 0056-0101. The file id is the group-wide identifier; provenance lives in the frontmatter (new field `projekt` plus gitlab_iid) and in the filename, so "gitops#61" still finds 0091. Bodies are copied verbatim; comments and history stay on GitLab, as with the 2026-08-11 management import. Both scripts learned the second dimension: spiegel_issues.py routes each file to its origin project, reopens issues that are open in the repo but closed on the board, and writes the new iid back after creating one; gruppenpruefung.py checks drift across all four trackers instead of management alone. What the mirror cannot decide stays a finding, not a silent state. Two things needed a hand, both recorded in the files: gitops#61 had no milestone (M1 - it is a live account-takeover path) and carried two area labels where the schema holds one. The Gitea migration footers in the imported bodies point at decommissioned trackers; their links are removed, the provenance sentence stays. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
79 lines
3.2 KiB
Markdown
79 lines
3.2 KiB
Markdown
---
|
|
type: issue
|
|
id: "0091"
|
|
status: open
|
|
created: 2026-08-11
|
|
milestone: M1
|
|
priority: high
|
|
area: security
|
|
projekt: gitops
|
|
gitlab_iid: "61"
|
|
related:
|
|
- "docs/adr/0011-enrollment-localpart-kollision-verweigern.md"
|
|
---
|
|
# Enrollment: kollidierender Localpart übernimmt bestehendes Konto (on_conflict: add)
|
|
|
|
> Adoptiert aus [gitops#61](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/61) (2026-08-18, ADR-0019). Kommentare und Verlauf bleiben dort; kanonisch ist ab jetzt diese Datei.
|
|
> Bei der Adoption ergänzt: Meilenstein M1 (fehlte auf GitLab); von den zwei
|
|
> area-Labels trägt das Schema eines — `security` bleibt, `authentik` entfällt.
|
|
|
|
## Befund
|
|
|
|
Der MAS-Upstream-Provider für Authentik verknüpfte eine neu registrierte
|
|
Upstream-Identität mit einem **bestehenden** lokalen Konto, sobald der
|
|
abgeleitete Localpart kollidiert:
|
|
|
|
```yaml
|
|
claims_imports:
|
|
localpart:
|
|
action: force
|
|
template: "{{ user.preferred_username }}"
|
|
on_conflict: add # <-- verknüpft statt abzubrechen
|
|
```
|
|
|
|
Zusammen mit Authentiks Benutzernamen-Eindeutigkeit, die **nur innerhalb von
|
|
Authentik** und **case-sensitive** greift, ergibt sich ein Übernahmeweg:
|
|
|
|
1. Ein Inhaber eines Einladungstokens registriert in Authentik einen Namen, der
|
|
als Matrix-Konto bereits existiert (oder eine Groß-/Kleinschreibungsvariante
|
|
davon — `boje` neben `Boje` ging live durch).
|
|
2. Authentiks Eindeutigkeit meldet keine Kollision, weil das Ziel-Matrix-Konto
|
|
für Authentik unsichtbar ist bzw. sich in der Schreibweise unterscheidet.
|
|
3. Beim ersten Login verknüpft MAS die neue Identität mit dem bestehenden Konto
|
|
— inklusive Räumen und Historie.
|
|
|
|
**Besonders exponiert:** Konten ganz ohne Upstream-Link, weil dort nichts
|
|
vorher da sein muss. Betroffen wären u. a. die Dienstkonten `draupnir`,
|
|
`alerts`, `maintenance-notify` sowie `frank`, `crank`, `shank`, `stank`,
|
|
`bojeledoggo`, `scanner-test`.
|
|
|
|
> Der Übernahmeweg wurde **nicht** aktiv ausprobiert (das wäre eine echte
|
|
> Kontoübernahme gewesen). Die Aussage stützt sich auf MAS' dokumentierte
|
|
> Semantik für `on_conflict` und auf die live reproduzierte case-sensitive
|
|
> Dublette `boje`/`Boje`.
|
|
|
|
## Wie es aufgefallen ist
|
|
|
|
Beim Anlegen eines Testkontos über den Einladungsflow entstand versehentlich
|
|
ein zweites Konto `boje` neben dem bestehenden `Boje` — kein Fehler, keine
|
|
Warnung. Die Nachprüfung der MAS-Claims-Konfiguration legte `on_conflict: add`
|
|
als Ursache offen.
|
|
|
|
## Fix (erledigt)
|
|
|
|
`on_conflict: fail` in `apps/production/custom-configs/mas-secret.yaml` — ein
|
|
kollidierender Localpart bricht die Provisionierung ab, statt zu verknüpfen.
|
|
Bestehende Verknüpfungen bleiben unberührt.
|
|
|
|
Commit `ef04d86`, gepusht nach git.lab. Rollt über Flux aus.
|
|
|
|
## Rest, bewusst offen
|
|
|
|
- **Authentiks case-sensitive Eindeutigkeit** verhindert `boje` neben `Boje`
|
|
weiterhin nicht. Der MAS-Fix fängt die Übernahme ab (Login schlägt fehl statt
|
|
zu verknüpfen), aber der Nutzer bekommt erst beim Login eine Fehlermeldung,
|
|
nicht schon bei der Registrierung. Eine Eindeutigkeitsprüfung (case-insensitive)
|
|
im Prompt-Stage des `matrix-invitation`-Flows wäre die saubere Ergänzung.
|
|
- **Verwaiste Zweitkonten** aus dieser Lücke (`apo2`, das gelöschte `boje`)
|
|
sind Altlasten, keine offene Verwundbarkeit.
|