Der framework-freie Kern ist fertig; Deployment-Key, Master-Key im Worker und der Nachweis am Datenbank-Dump haengen an Datenbank und Worker und kommen mit #007. Die Entscheidungen (16 bcrypt-Runden, Fehlercodes, RSA-Mindestlaenge abschaltbar fuers Beobachten, Umschlag-Format, Dateirechte des Master-Keys) stehen im Issue, damit die Anbindung nicht raten muss. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.6 KiB
3.6 KiB
#006 Verschlüsselte Ablage und OpenSSH-Schlüsselformat
Status: in Arbeit Meilenstein: v0.1.0 Labels: sicherheit Geschätzt: 4 h Tatsächlich: –
Ziel
Envelope Encryption für Private Keys mit Master-Key aus Datei; eigene Erzeugung und Serialisierung von OpenSSH-Schlüsseln ohne temporäre Dateien; Deployment-Key der Instanz.
Aufgaben
- Master-Key aus Datei laden (32 Byte roh, Base64 oder Hex; Rechteprüfung) –
masterKeyLaden - Master-Key aus
SSHKV_MASTER_KEY_FILEnur im Worker anbinden - AES-256-GCM, DEK je Schlüssel, AAD = Schlüssel-ID + Fingerprint, Master-Key-Version
- ed25519 und RSA-4096 erzeugen (Node
crypto), OpenSSH-Format schreiben und lesen (optional Passphrase: bcrypt-pbkdf + aes256-ctr) - Fingerprint SHA256 wie
ssh-keygen -l - Deployment-Key beim ersten Start erzeugen
- Log-Redaction (
schwaerzen; Einbau in Logger/Protokoll folgt)
Akzeptanzkriterien
ssh-keygen -y -fliest erzeugte Schlüssel (mit und ohne Passphrase)- Fingerprints identisch zu
ssh-keygen -lf - Datenbank-Dump enthält keinen Klartext-Schlüssel
Abhängigkeiten
#003
Notizen / Entscheidungen
- Kern fertig; Anbindung an Datenbank/Worker folgt mit #007. Offen sind Deployment-Key beim ersten Start, Master-Key nur im Worker laden und der Nachweis „Datenbank-Dump enthält keinen Klartext“.
- Module:
src/lib/ssh/openssh.ts(Erzeugen/Schreiben/Lesen, Fingerprint, Public-Key-Zeilen),src/lib/krypto/umschlag.ts(Envelope Encryption, Master-Key laden),src/lib/protokoll-schwaerzen.ts(Redaction). Alle framework-frei. - Eigener Serializer für
openssh-key-v1stattssh-keygen: keine Private Keys als Temp-Dateien. Die Tests prüfen gegen das echtessh-keygen(beide Richtungen, mit/ohne Passphrase). - Passphrase:
aes256-ctr+bcryptmit 16 Runden (ssh-keygen nimmt heute 24).bcrypt-pbkdfist reines JavaScript; 16 Runden halten das im Worker unter einer Sekunde. Beim Lesen gilt die Rundenzahl aus der Datei (Obergrenze 1000 gegen absichtlich teure Importe). Andere Cipher (z. B.aes256-gcm@openssh.comviassh-keygen -Z) werden mit klarer Meldung abgelehnt. Private-Key-Import nur für ed25519 und RSA. SchluesselFormatFehlerträgt einencode(ungueltig,nicht_unterstuetzt,passphrase_fehlt,passphrase_falsch,zu_schwach); Meldungen sind feste Sätze ohne Eingabe.- RSA-Mindestlänge 2048 Bit standardmäßig in
publicKeyZeileLesenundprivateKeyLesen;{ rsaMindestBits: 0 }für das reine Beobachten vorhandenerauthorized_keys(Drift). - Kommentare mit Steuerzeichen werden abgelehnt, sonst ließe sich über einen Kommentar eine zweite
Zeile in
authorized_keyseinschleusen. - Umschlag-Format je Puffer:
Version (1) | IV (12) | Tag (16) | Daten. AAD Klartext =zusatz(vorgesehen:schluessel:<id>:<fingerprint>), AAD DEK =sshkv-dek:v<masterKeyVersion>.versiegeln(..., masterKeyVersion = 1); beim Öffnen muss der Aufrufer den Master-Key passend zur Version wählen. - Master-Key-Datei mit Gruppe/Welt-Leserecht → Abbruch, außer
SSHKV_MASTER_KEY_UNSICHER_ERLAUBT=1(dann Warnung). Achtung Docker: Secrets ohne Swarm sind Bind-Mounts mit den Rechten der Host-Datei – dortchmod 400und passenden Eigentümer setzen. - Schwärzen greift auf Feldnamen, die einen der Wortstämme
privat,passwort,password,passphrase,secret,geheimnis,token,masterkey,authorization,cookieenthalten (nicht nur als Präfix), sowie auf PEM-Private-Keys in jeder Zeichenkette (auch abgeschnitten, auch inmessage/stackvon Fehlern). Rohe Bytes werden zu[Binärdaten].