florian.wildeandClaude Opus 5.5 f18fd4ec06 feat(rotation): laufende Rotation abbrechen (#032)
Bisher liess sich eine angefangene Rotation nur zu Ende fuehren. Wer
merkt, dass der neue Schluessel nicht passt, braucht einen Weg zurueck,
ohne den alten anzufassen.

"Rotation abbrechen" (Rotationsseite und Seite des Nachfolgers) merkt
den neuen Schluessel ueber den bestehenden Widerruf aus #024 vor; er
kann schon ausgerollt sein, deshalb folgen Dry-Run und Anwenden wie
sonst. Der alte bleibt aktiv und unveraendert. Wo beide denselben
Alias tragen, zeigt die config danach wieder auf die alte Datei, weil
privat.ts nur die verbleibenden Zuweisungen in den Block schreibt.

Zustandsmodell: kein neues Feld. Ein Nachfolger im Widerruf (oder
widerrufen) ist eine abgebrochene Rotation; vorgaengerId bleibt fuer
die Historie, der Abbruch steht als schluessel.rotation.abgebrochen im
Protokoll (in derselben Transaktion wie das Vormerken, dafuer nimmt
widerrufEinleiten optional einen Zusatzschritt an). Abbrechen geht nur,
solange der alte Schluessel noch nicht entfernt wird. widerrufAbschliessen
macht aus dem Widerruf des alten Schluessels kein ROTIERT mehr, wenn
der Nachfolger selbst im Widerruf ist. Weil vorgaengerId eindeutig
ist, gibt es nach einem Abbruch keinen zweiten Nachfolger; Seite und
Fehlermeldung sagen das.

Tests: DB-Tests fuer Abbruch, Idempotenz, Sperren und Status;
Integrationstest gegen echte Ziele (neuer Key ausgerollt, abbrechen,
neuer weg, alter in authorized_keys, ssh zu-b von A geht); E2E fuer
den Ablauf im Browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:45:11 +02:00

SSHKeyVault (sshkv)

Selbst gehostete Weboberfläche zur zentralen Verwaltung von SSH-Schlüsseln: Schlüsselpaare erzeugen und verwalten, Public Keys in authorized_keys verteilen, Private Keys gezielt auf andere Hosts ausrollen, Ist- und Soll-Zustand abgleichen – alles revisionssicher protokolliert.

Stand 0.5.0: alle fünf Phasen aus docs/PLAN.md umgesetzt – Hosts mit Host-Key-Prüfung und Bootstrap, Schlüssel, Ausrollen von Public und Private Keys mit Dry-Run, Host-zu-Host-Assistent, Abgleich, Rotation, Widerruf, Zuweisungsmatrix, Audit-Log, Benachrichtigungen. 1.0.0 nach der Abnahme.

Sicherheit vorab

SSHKeyVault hat root-Zugriff auf alle verwalteten Hosts. Deshalb:

  • nur im internen Netz bzw. VPN betreiben, mit Reverse Proxy und TLS davor;
  • den Master-Key (SSHKV_MASTER_KEY_FILE) getrennt von der Datenbank sichern – ohne ihn ist ein Datenbank-Backup wertlos, und mit ihm zusammen gibt es alle Private Keys preis;
  • Private Keys liegen nur verschlüsselt in der Datenbank (AES-256-GCM, Envelope Encryption); entschlüsseln kann ausschließlich der Worker, der Webprozess hat den Master-Key nicht.

Mehr dazu in docs/betrieb/sicherheit.md (mit Bedrohungsanalyse und Notfallplan) und docs/betrieb/sicherung.md.

Dokumentation

Installation (Docker Compose)

cp .env.example .env              # Werte eintragen, siehe Kommentare
openssl rand -base64 48           # → SSHKV_APP_SECRET
mkdir -p geheim && head -c 32 /dev/urandom > geheim/master.key
sudo chown 1001:1001 geheim/master.key && sudo chmod 400 geheim/master.key
docker compose up -d

Die Oberfläche lauscht auf 127.0.0.1:3400 (SSHKV_BIND, SSHKV_PORT). Beim ersten Start legt der Dienst migrate das Schema, den Notfall-Admin (SSHKV_BREAKGLASS_*) und die eingebauten Vorlagen an; der Worker erzeugt den Deployment-Key der Instanz.

Anmeldung: über authentik (SSHKV_OIDC_*, Rollen über die Gruppen sshkv-admins, sshkv-operators, sshkv-readers). Der Notfall-Admin richtet bei der ersten Anmeldung TOTP ein.

Einen Host aufnehmen

  1. Hosts → + Host anlegen (Name, Adresse, Port; Anmeldung als Dienstbenutzer sshkv mit sudo – empfohlen – oder direkt als root).
  2. Host-Key abrufen, den Fingerprint am Host vergleichen (ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub) und vertrauen.
  3. Bootstrap: einmalig per Passwort (wird nicht gespeichert) oder den angezeigten Befehl auf dem Host einfügen und „Einrichtung prüfen“.

Entwicklung

Node 24, pnpm 12, Docker. Konventionen und Befehle: CLAUDE.md.

pnpm install
pnpm db:up && pnpm db:migrate && pnpm db:seed
pnpm test:ziele:up                # SSH-Testziele + Mock-OIDC
pnpm build && pnpm start          # http://localhost:3400
pnpm worker                       # zweites Terminal
pnpm test && pnpm test:integration && pnpm test:e2e
S
Description
No description provided
Readme
12 MiB
Languages
TypeScript 98.4%
Shell 0.6%
JavaScript 0.4%
HTML 0.2%
Dockerfile 0.2%
Other 0.2%