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>
3.5 KiB
3.5 KiB
#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: VorgangsartenSCHLUESSEL_ERZEUGEN,SCHLUESSEL_IMPORTIEREN,PRIVATE_KEY_LOESCHEN(für #014 gleich mit), CHECKschluessel_slug_gueltig(^[a-z0-9-]{1,64}$, der Slug landet in Dateinamen) undschluessel_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 mitSSHKV_APP_SECRETverschlüsselt im Job (geheim), nie inVorgang.eingabe; der Worker löscht den Job danach. Der Worker prüft die Metadaten erneut. - Kategorie: Erzeugen und Paar-Import legen immer
DIENSTan. Personen-Keys speichert sshkv nie mit Private Key (DB-CHECK), Deployment-Keys verwaltet der Worker selbst. Der Public-Key-Import kenntPERSONundDIENST. - 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:
RSA4096nur bei genau 4096 Bit, sonstANDERER(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/WIDERRUFENsetzen #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 CHECKschluessel_umschlag_vollstaendigkoppelt sie an das Chiffrat) – das Chiffrat wird im Web nie selektiert. - Grenze abgesichert:
tests/schluessel-grenze.test.tsverlangt für jeden zeilenlieferndenprisma.schluessel.*-Aufruf außerhalb vonsrc/workereinselectund verbietetschluessel: trueals Relation;tests/schluessel.test.tsprü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.tsxundPrivateAusrollenAktion.tsx, Props{ schluesselId: string; darf: boolean }, rendernnull. - Personen-Keys zeigen im Detail nur die Karte „Public Key ausgerollt auf“ (eine Private-Karte wäre immer leer).
- Prototyp
/schluessel/beispielsamtsrc/beispiel/schluessel.tsentfernt; die Übersicht (noch Prototyp, #026) verlinkt auf/schluessel.