--- type: issue id: "0015" status: in-progress created: 2026-08-01 milestone: M2 priority: medium due: 2026-08-31 host: cfgmon area: security gitlab_iid: "15" related: [docs/issues/0027-audit-01-acht-widersprueche-aus-dem-labnet-02.md] --- # CFGMON-15: Token-Hygiene — Einmal-Tokens der LABNET-02-Nacht widerrufen > Import aus [management#15](https://git.lab/axion1337.chat/management/-/issues/15) (2026-08-11). Kommentare und Verlauf bleiben dort; kanonisch ist ab jetzt diese Datei (ADR-0012). Gemeldet von der CFGMON-Session am Ende der LABNET-02-Nacht. Während der Arbeit entstanden **vier Einmal-Tokens** für Issue-Kommentare/Pushes, dazu existiert noch das **erste git.lab-Token** aus dem Erstzugang. Alle sind nach Abschluss von LABNET-02 funktionslos. **Zu tun:** Bestand aufnehmen (Gitea-Access-Tokens + GitLab-PATs), nicht mehr benötigte widerrufen, verbleibende mit Ablaufdatum und sprechendem Namen versehen. ⚠️ **Randbedingung aus der Mirror-Diskussion:** Welcher Token in den Push-Mirrors der fünf gespiegelten Repos hinterlegt ist, ist derzeit **nicht rekonstruierbar** (die API maskiert ihn, in keiner Session dokumentiert). Ein Widerruf kann deshalb still einen Mirror brechen. Vor der Rotation: entweder die Mirror-Credentials bewusst neu setzen, oder nach dem Widerruf jeden Mirror-Status einmal prüfen (`GET /projects//remote_mirrors` → `last_error`). ## Bestandsaufnahme 2026-08-15 ### git.lab-PATs: 24 Stück, davon 13 aktiv Abgefragt über `GET /personal_access_tokens` — **nur Metadaten, keine Werte** (die gibt die API ohnehin nur bei der Erzeugung heraus). `last_used_at` ist dabei der eigentliche Hebel: er trennt „wird gebraucht" von „liegt herum". **Aktiv und nachweislich in Gebrauch — NICHT anfassen:** | id | Name | Scopes | zuletzt genutzt | |---|---|---|---| | 6 | gitlab claude token | api | 2026-08-15 (heute — Session-Zugang) | | 24 | wiki-canonize | write_repository | 2026-08-15 (CI-Kanonisierung) | | 8 | Gitea-push-token | api, write_registry | 2026-08-14 | | 19 | management#31 | read_api | 2026-08-14 | **Aktiv, aber NIE benutzt — die eigentliche Hygiene-Baustelle:** | id | Name | Scopes | angelegt | |---|---|---|---| | 18 | oskar light | api, read_api, **manage_runner, k8s** | 2026-08-04 | | 9 | registry-cleanup | api, read/write_registry | 2026-08-03 | | 11 | herold-hive | read/write_repository | 2026-08-04 | | 15 | oskar read | read_service_ping, read_user, … | 2026-08-04 | | 23 | wiki-canonize | write_repository | 2026-08-13 — **Dublette zu id=24** | **Aktiv, einmal benutzt, seither still:** id=4 `tabby` (27.07.), id=10 `SORB API` (04.08.), id=13 `herold` (04.08.), id=17 `oskar analyse` (09.08.). **Bereits inaktiv (nichts zu tun):** ids 1, 2, 3, 5, 7, 12, 14, 16, 20, 21, 22. Auffällig ist ein Muster: mehrere Namen existieren **doppelt**, einmal aktiv und einmal inaktiv (`herold`, `oskar read`, `oskar analyse`, `wiki-canonize`) — offenbar wurde jeweils neu erzeugt, ohne das alte zu widerrufen. Genau daraus entsteht der Wildwuchs, den dieses Issue adressiert. ### Push-Mirrors: alle gesund, Konto aber weiterhin unbekannt Sechs Mirrors, **alle `finished`, kein `last_error`** (Stand 2026-08-15): ThreadNet-Web, gitops, thread-net-git, threadnet-call, threadnet-operating, management. ⚠️ Die Warnung des Issues bestätigt sich: GitLab maskiert in `remote_mirrors` **beide** Teile der URL (`https://*****:*****@rohana…`). Es ist also **weder Konto noch Token rekonstruierbar**. Und: die Mirrors authentifizieren sich gegen **Gitea**, das gesuchte Credential ist damit ein **Gitea**-Token, kein git.lab-PAT — die PAT-Liste oben kann die Frage gar nicht beantworten. *(Nebenbefund: `gameserver` hat wirklich keinen Mirror → bestätigt #0032. `notfallhandbuch` bewusst nicht → ADR-0016. `threadnet-wiki` braucht keinen, es läuft in Gegenrichtung.)* ### Empfehlung — Reihenfolge zählt 1. **Mirror-Credential bewusst neu setzen, bevor irgendetwas widerrufen wird.** Ein dedizierter Gitea-Token (Name z.B. `gitlab-mirror`, Scope `write:repository`, mit Ablaufdatum), auf allen sechs Mirrors hinterlegt. Danach ist bekannt und dokumentiert, woran sie hängen — die Unklarheit verschwindet, statt umschifft zu werden. 2. **Erst dann Gitea-Alttokens widerrufen**, anschließend alle sechs Mirrors einmal prüfen (`GET /projects//remote_mirrors` → `last_error`). 3. **git.lab-PATs aufräumen:** die fünf nie benutzten zuerst (id 18, 9, 11, 15, 23) — id=18 ist wegen `manage_runner`+`k8s` der unangenehmste Fund. Danach die vier Einmal-Nutzer (4, 10, 13, 17), sofern die zugehörigen Werkzeuge nicht mehr laufen. 4. **Verbleibende** mit sprechendem Namen **und Ablaufdatum** versehen — mehrere laufen Ende August/Anfang September ohnehin aus, das ist der natürliche Zeitpunkt. **Die Widerrufe selbst gehören sorb** (Credentials legt/entfernt der Mensch); ich habe bewusst nichts widerrufen — bei Namen wie `herold`, `oskar`, `tabby` ist von hier nicht erkennbar, ob dahinter ein laufendes Werkzeug steht. `last_used_at = None` heißt „nie benutzt", nicht „nicht gebraucht": ein hinterlegter, aber noch nicht ausgelöster Token sieht genauso aus. ### Bezug zu #0027 (W4/W5) - **W5 aufgelöst:** Die Secrets-Regel in `AGENTS.md` hat jetzt eine **Bootstrap-Ausnahme** — auf einem Host, wo sorb die Datei nicht selbst anlegen kann, darf eine Session das Credential schreiben, aber es gilt als exponiert (Rotationspflicht), wird mit Pfad+Zweck festgehalten und bekommt ein fälliges Issue. Damit ist die Regel erfüllbar, ohne sie zu brechen. - **W4 Punkt 5** (Rotation der in der LABNET-02-Nacht exponierten Werte) ist inhaltlich **dieses Issue** — der WG-Private-Key gehört ausdrücklich dazu und ist oben **nicht** abgedeckt (er ist kein API-Token): separat rotieren. - **W4 Punkt 4** (Repo-Zuhause für `lab.conf`, systemd-Drop-in, Root-CA) ist **nachweislich offen**: `gitops:host-config/` existiert als Muster, enthält aber nur `maintenance-notify`. Die Schließung von #16 war für diesen Punkt also verfrüht.