Einen Schlüssel zu tauschen soll keinen Ausfall riskieren: Der Nachfolger übernimmt alle aktiven Zuweisungen, wird ausgerollt und per Verbindungstest geprüft – erst wenn alle Tests seit dem letzten Ausrollen grün sind, entfernt der Widerruf aus #024 den alten Schlüssel, der dann als ROTIERT endet. Private Keys bekommen einen neuen Pfad (-rJJJJMMTT) bei gleichem Alias. Damit ssh den neuen nimmt, schreibt privat.ts je Alias nur noch einen config-Eintrag; die jüngste Zuweisung gewinnt. Der Worker setzt vorgaengerId schon beim Erzeugen, so ist die Kette auch nach einem Abbruch vollständig und die Schrittfolge wiederaufnehmbar. Personen-Keys ohne Private Key in sshkv bekommen nur einen Hinweis: dafür braucht es einen neuen Public Key von der Person. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2.9 KiB
2.9 KiB
#023 Geführte Rotation
Status: erledigt Meilenstein: v0.4.0 Labels: backend, ui Geschätzt: 3 h Tatsächlich: 0 h 20 min
Ziel
Neuer Schlüssel an allen Verwendungen, Test, alter entfernt.
Aufgaben
- „Rotieren“ auf der Schlüsselseite, Schrittfolge
/schluessel/[id]/rotieren(wiederaufnehmbar) - Neuer Schlüssel gleichen Typs, Name „… (rotiert TT.MM.JJJJ)“,
vorgaengerId= alter - Zuweisungen übernehmen: Public gleiche Ziele/Optionen, Private gleicher Host/Benutzer/Alias mit neuem Pfad
- Dry-Run + Ausrollen, Verbindungstests, erst dann den alten widerrufen (#024) →
ROTIERT - Personen-Key ohne Private Key: nur Hinweis „neuer Public Key nötig“
- Rotationskette auf der Schlüsselseite (Vorgänger/Nachfolger verlinkt)
Akzeptanzkriterien
- DB-Tests: Schritte, Reihenfolge, Rechte, Namen/Pfade (
tests/rotation.test.ts) - Integrationstest: neuer Schlüssel funktioniert, alter von beiden Hosts weg,
ssh <alias>geht weiter - E2E im Browser (
tests/e2e/rotation.spec.ts), Screenshotrotation-desktop.png
Abhängigkeiten
#020, #024
Notizen / Entscheidungen
- Fünf Schritte: Neuer Schlüssel → Zuweisungen übernehmen → Dry-Run & Ausrollen → Verbindungstests →
Alten widerrufen. Der aktuelle Schritt wird aus der Datenbank errechnet (
rotationsStand), deshalb lässt sich die Rotation jederzeit neu laden und fortsetzen; jeder Schritt ist idempotent. - Kette sofort: Der Worker setzt
vorgaengerIdschon beim Erzeugen (neues Feld in der Vorgangs-Eingabe) – auch ein abgebrochener Browser hinterlässt keinen verwaisten Schlüssel.vorgaengerIdist eindeutig: zwei gleichzeitige Rotationen scheitern verständlich. - Gleicher Alias, zwei Zuweisungen:
privat.tsschreibt je Alias genau einen config-Eintrag, die jüngste Zuweisung gewinnt (an der Position der ersten). So zeigtssh <alias>nach dem Ausrollen auf die neue Datei, während die alte bis zum Widerruf daneben liegt. - Neuer Pfad:
<alter Pfad ohne -rJJJJMMTT>-rJJJJMMTT, bei Kollision mit laufender Nummer – auch entfernte Zuweisungen belegen einen Pfad (eindeutiger Index über alle Zustände). - Grün heißt aktuell: Der alte Schlüssel wird nur widerrufen, wenn für jede Private-Zuweisung mit
Alias ein erfolgreicher
VERBINDUNGSTESTnach dem letzten Ausrollen vorliegt (Server prüft das). Ohne Private-Zuweisung mit Alias entfällt der Test. - Abschluss: Widerruf aus #024 ohne Zielkonten (der Nachfolger nutzt sie weiter); ein aktiver
Nachfolger macht aus
WIDERRUFENden StatusROTIERT. - Ablaufdatum: Der Nachfolger erbt es nur, wenn es in der Zukunft liegt. Eine Passphrase wird nicht übernommen (sshkv erzeugt ohne).
- Rechte:
schluesselVerwalten+publicKeyAusrollen, bei Private-ZuweisungenprivateKeyAusrollen. Deployment-Key: eigene Rotation (später).