Files
sshkeyvault/docs/issues/012-schluessel-verwalten.md
T
florian.wildeandClaude Opus 5.5 263143134f feat(schluessel): erzeugen, importieren, exportieren (#012)
Schluessel werden jetzt verwaltet statt nur im Prototyp gezeigt: Liste
mit Filter, Anlegen (erzeugen oder importieren), Detail nach dem
Prototyp aus #002, Bearbeiten der Metadaten und Download <slug>.pub.

Warum so:
- Erzeugen und Import eines Paars laufen als Vorgang im Worker, weil
  nur er den Master-Key hat. Passphrase und importierter Private Key
  reisen wie das Bootstrap-Passwort mit SSHKV_APP_SECRET verschluesselt
  im Job, nie in Vorgang.eingabe; der Worker loescht den Job danach.
- Ein reiner Public Key ist kein Geheimnis und wird direkt im Web
  angelegt, mit verstaendlicher Meldung bei einem Duplikat.
- Das Web liest nie das Chiffrat: ob ein Private Key gespeichert ist,
  verraet masterKeyVersion (per CHECK an das Chiffrat gekoppelt). Ein
  struktureller Test verlangt fuer jede zeilenliefernde Abfrage auf
  Schluessel ausserhalb des Workers ein festes select.
- Migration: Vorgangsarten fuer Erzeugen, Import und (fuer #014) das
  Loeschen des Private Keys; CHECKs fuer den Slug (landet in
  Dateinamen) und "geloescht nur ohne Chiffrat".
- Platzhalter PublicAusrollenAktion/PrivateAusrollenAktion fuer #016/#017.

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

3.5 KiB
Raw Blame History

#012 Schlüssel erzeugen, importieren, exportieren

Status: erledigt Meilenstein: v0.2.0 Labels: backend, ui Geschätzt: 4 h Tatsächlich: 0 h 25 min

Ziel

Schlüsselliste und -formular: erzeugen (ed25519, rsa-4096), importieren (Public oder Paar), exportieren; Kategorien, Tags, Ablaufdatum.

Aufgaben

  • Liste mit Filter
  • Erzeugen-Dialog
  • Import mit Prüfung
  • Export Public Key
  • Schlüsseldetail-Gerüst mit Verwendungen

Akzeptanzkriterien

  • Private Keys erscheinen nie in Listen-Antworten

Abhängigkeiten

#006

Notizen / Entscheidungen

  • Migration 20261012100000_schluessel_vorgaenge: Vorgangsarten SCHLUESSEL_ERZEUGEN, SCHLUESSEL_IMPORTIEREN, PRIVATE_KEY_LOESCHEN (für #014 gleich mit), CHECK schluessel_slug_gueltig (^[a-z0-9-]{1,64}$, der Slug landet in Dateinamen) und schluessel_geloescht_ohne_private_key.
  • Erzeugen und Paar-Import laufen im Worker (src/worker/ablaeufe/schluessel.ts). Das Web prüft nur Metadaten (Slug frei, Person/Vorlage vorhanden, Ablauf nicht in der Vergangenheit) und reiht den Vorgang ein. Passphrase und importierter Private Key reisen wie das Bootstrap-Passwort mit SSHKV_APP_SECRET verschlüsselt im Job (geheim), nie in Vorgang.eingabe; der Worker löscht den Job danach. Der Worker prüft die Metadaten erneut.
  • Kategorie: Erzeugen und Paar-Import legen immer DIENST an. Personen-Keys speichert sshkv nie mit Private Key (DB-CHECK), Deployment-Keys verwaltet der Worker selbst. Der Public-Key-Import kennt PERSON und DIENST.
  • Passphrase: beim Erzeugen optional; gespeichert wird dann der passphrasengeschützte OpenSSH-Key (passphraseGeschuetzt = true). Beim Import dient sie nur zum Lesen von Public Key und Fingerprint und wird verworfen; gespeichert wird der Key so, wie er kam. Hinweis in der Oberfläche: „Für automatische Anmeldungen (Host-zu-Host) ungeeignet.“
  • Typ: RSA4096 nur bei genau 4096 Bit, sonst ANDERER (z. B. RSA-3072, ecdsa). Die RSA- Mindestlänge 2048 gilt beim Import.
  • Slug: aus dem Zweck abgeleitet (Umlaute gefaltet), bei Kollision -2, -3 …; ein ausdrücklich gewünschter Kurzname muss frei sein. Slug, Typ und Kommentar sind danach nicht mehr änderbar – sie stehen schon in Dateinamen und authorized_keys-Zeilen.
  • Status von Hand nur AKTIV ↔ ABGELAUFEN; ROTIERT/WIDERRUFEN setzen #023/#024, Deployment-Keys sind ausgenommen (sonst erzeugte der Worker beim Start einen neuen).
  • Ablaufdatum ohne Angabe aus Vorlage.standardLaufzeitTage.
  • „Private Key gespeichert?“ liest das Web aus masterKeyVersion (der CHECK schluessel_umschlag_vollstaendig koppelt sie an das Chiffrat) – das Chiffrat wird im Web nie selektiert.
  • Grenze abgesichert: tests/schluessel-grenze.test.ts verlangt für jeden zeilenliefernden prisma.schluessel.*-Aufruf außerhalb von src/worker ein select und verbietet schluessel: true als Relation; tests/schluessel.test.ts prüft, dass weder Vorgang, Protokoll noch pg-boss-Job nach Erzeugen/Import den Key oder die Passphrase enthalten.
  • Platzhalter für #016/#017: src/app/(app)/schluessel/[id]/PublicAusrollenAktion.tsx und PrivateAusrollenAktion.tsx, Props { schluesselId: string; darf: boolean }, rendern null.
  • Personen-Keys zeigen im Detail nur die Karte „Public Key ausgerollt auf“ (eine Private-Karte wäre immer leer).
  • Prototyp /schluessel/beispiel samt src/beispiel/schluessel.ts entfernt; die Übersicht (noch Prototyp, #026) verlinkt auf /schluessel.