diff --git a/AGENTS.md b/AGENTS.md index 84de8dc..757d08d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -156,6 +156,17 @@ Ohne Lab-Zugang: dieses Repo ist als Push-Mirror unter Dateipfade (z. B. `~/.config/gitlab-lab/token`) oder maskierte CI-Variablen. Die Trennung ist „Credential vs. Config": nicht-geheime Konfiguration wird normal committet. +- **Bootstrap-Ausnahme** (aus #0027/W5): Auf einem Host, auf dem sorb die + Datei nicht selbst anlegen kann und kein anderer Übergabekanal + existiert, **darf** eine Session ein Credential schreiben — sonst ist + die Inbetriebnahme unmöglich, und die Regel wäre nur durch Verstoß + erfüllbar. Es gilt dann zwingend: (a) der Wert **ist damit exponiert**, + also **rotationspflichtig**, sobald der reguläre Weg steht; (b) im AAR + oder Issue wird festgehalten **welches** Credential **wohin** + geschrieben wurde (nur Pfad und Zweck, nie der Wert); (c) die Rotation + bekommt ein Issue mit Fälligkeit — „später mal" zählt nicht. + Die Ausnahme deckt das **Ablegen**, nicht das Anzeigen: auch im + Bootstrap wird der Wert nicht in Logs, Chat oder Commits sichtbar. ### Commit-Konventionen diff --git a/STATUS.md b/STATUS.md index 947da10..84d80ba 100644 --- a/STATUS.md +++ b/STATUS.md @@ -13,7 +13,7 @@ Verteilung: M1 6 · M2 18 · M4 2 · M5 4 | [0008](docs/issues/0008-cfgmon-03-prometheus-remote-write-und-loki.md) | waiting | M1 | medium | CFGMON-03: Prometheus-Remote-Write und Loki öffentlich ohne Auth — Weg A, nachgelagerte Prüfung | | [0009](docs/issues/0009-cfgmon-04-grafana-admin-credentials-aus-env.md) | open | M2 | low | CFGMON-04: Grafana-Admin-Credentials aus .env gelten nicht für die HTTP-API | | [0014](docs/issues/0014-cfgmon-14-root-zugang-ueber-die-docker-gruppe.md) | open | M2 | low | CFGMON-14: Root-Zugang über die docker-Gruppe umgeht sudo und hinterlässt keine Spur | -| [0015](docs/issues/0015-cfgmon-15-token-hygiene-einmal-tokens-der.md) | next | M2 | medium | CFGMON-15: Token-Hygiene — Einmal-Tokens der LABNET-02-Nacht widerrufen | +| [0015](docs/issues/0015-cfgmon-15-token-hygiene-einmal-tokens-der.md) | in-progress | M2 | medium | CFGMON-15: Token-Hygiene — Einmal-Tokens der LABNET-02-Nacht widerrufen | | [0018](docs/issues/0018-doc-01-wiki-rollout-abschliessen-ci-freigaben.md) | open | M2 | low | DOC-01: Wiki-Rollout abschließen — CI-Freigaben, Zeitplan, Dokploy-Stack, wiki.lab | | [0019](docs/issues/0019-doc-02-veralteten-wiki-branch-im-gitops-repo.md) | open | M2 | low | DOC-02: Veralteten `wiki`-Branch im gitops-Repo entfernen? | | [0021](docs/issues/0021-overmind-03-windows-build-vm-verschwindet-ci.md) | waiting | M2 | medium | OVERMIND-03: Windows-Build-VM verschwindet — CI kann sie nur starten, nicht anlegen | diff --git a/docs/issues/0015-cfgmon-15-token-hygiene-einmal-tokens-der.md b/docs/issues/0015-cfgmon-15-token-hygiene-einmal-tokens-der.md index 2cb9186..3d10ad5 100644 --- a/docs/issues/0015-cfgmon-15-token-hygiene-einmal-tokens-der.md +++ b/docs/issues/0015-cfgmon-15-token-hygiene-einmal-tokens-der.md @@ -1,7 +1,7 @@ --- type: issue id: "0015" -status: next +status: in-progress created: 2026-08-01 milestone: M2 priority: medium @@ -9,7 +9,7 @@ due: 2026-08-31 host: cfgmon area: security gitlab_iid: "15" -related: [] +related: [docs/issues/0027-audit-01-acht-widersprueche-aus-dem-labnet-02.md] --- # CFGMON-15: Token-Hygiene — Einmal-Tokens der LABNET-02-Nacht widerrufen @@ -22,3 +22,87 @@ Während der Arbeit entstanden **vier Einmal-Tokens** für Issue-Kommentare/Push **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. diff --git a/docs/issues/0027-audit-01-acht-widersprueche-aus-dem-labnet-02.md b/docs/issues/0027-audit-01-acht-widersprueche-aus-dem-labnet-02.md index d93f16f..49f6359 100644 --- a/docs/issues/0027-audit-01-acht-widersprueche-aus-dem-labnet-02.md +++ b/docs/issues/0027-audit-01-acht-widersprueche-aus-dem-labnet-02.md @@ -245,3 +245,30 @@ Dienst neu laden, mit `resolvectl domain` gegenprüfen. **Stand der acht Widersprüche: W1, W2, W3, W6, W7, W8 erledigt — offen nur noch W4 und W5** (Schließung von #16 bestätigen bzw. Punkte 4+5 reaktivieren; Bootstrap-Klausel in der Secrets-Regel). Beide hängen an der Schlüsselrotation und passen zu #0015. + +## W5 erledigt / W4 präzisiert — 2026-08-15 + +**W5 erledigt.** Die Secrets-Regel in `AGENTS.md` hat jetzt eine **Bootstrap-Ausnahme**: Wo +sorb die Datei auf dem Zielhost nicht selbst anlegen kann und kein anderer Übergabekanal +existiert, darf eine Session das Credential schreiben. Bedingungen: der Wert gilt damit als +**exponiert und rotationspflichtig**, es wird festgehalten **welches** Credential **wohin** +ging (Pfad + Zweck, nie der Wert), und die Rotation bekommt ein Issue mit Fälligkeit. Die +Ausnahme deckt **nur das Ablegen** — Anzeigen in Logs, Chat oder Commits bleibt verboten. + +Damit ist der strukturelle Widerspruch aufgelöst: Die Regel war bisher auf einem headless Host +**nur durch Verstoß erfüllbar**, was sie als Regel entwertet hat. Jetzt benennt sie den Fall +und knüpft ihn an Auflagen. + +**W4 — zwei Teile, unterschiedlicher Stand:** + +- **Punkt 5 (Rotation)** ist inhaltlich **#0015**, das gerade bearbeitet wird (Bestandsaufnahme + der 24 git.lab-PATs und der sechs Mirrors liegt dort). ⚠️ Der in der LABNET-02-Nacht + exponierte **WireGuard-Private-Key** ist davon **nicht** abgedeckt (kein API-Token) und muss + separat rotiert werden. +- **Punkt 4 (Repo-Zuhause für `lab.conf`, systemd-Drop-in, Root-CA)** ist **nachweislich + offen**: `gitops:host-config/` existiert als genau dafür gedachtes Muster, enthält aber nur + `maintenance-notify`. Die Schließung von #16 war für diesen Punkt verfrüht — hier braucht es + keine Bestätigung, sondern die Arbeit. + +**Damit bleibt von den acht Widersprüchen nur W4 offen**, und zwar als konkrete Aufgabe statt +als Klärungsfrage: Host-Config ins Repo (Punkt 4) + WG-Key rotieren (Punkt 5, neben #0015).