Merge branch 'phase/006-geheimnisse-schluesselformat' (Kern)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# #006 Verschlüsselte Ablage und OpenSSH-Schlüsselformat
|
||||
**Status:** offen
|
||||
**Status:** in Arbeit
|
||||
**Meilenstein:** v0.1.0
|
||||
**Labels:** sicherheit
|
||||
**Geschätzt:** 4 h **Tatsächlich:** –
|
||||
@@ -8,19 +8,50 @@
|
||||
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 `SSHKV_MASTER_KEY_FILE` (32 Byte), nur im Worker
|
||||
- [ ] 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`
|
||||
- [x] Master-Key aus Datei laden (32 Byte roh, Base64 oder Hex; Rechteprüfung) – `masterKeyLaden`
|
||||
- [ ] Master-Key aus `SSHKV_MASTER_KEY_FILE` nur im Worker anbinden
|
||||
- [x] AES-256-GCM, DEK je Schlüssel, AAD = Schlüssel-ID + Fingerprint, Master-Key-Version
|
||||
- [x] ed25519 und RSA-4096 erzeugen (Node `crypto`), OpenSSH-Format schreiben und lesen (optional Passphrase: bcrypt-pbkdf + aes256-ctr)
|
||||
- [x] Fingerprint SHA256 wie `ssh-keygen -l`
|
||||
- [ ] Deployment-Key beim ersten Start erzeugen
|
||||
- [ ] Log-Redaction
|
||||
- [x] Log-Redaction (`schwaerzen`; Einbau in Logger/Protokoll folgt)
|
||||
|
||||
## Akzeptanzkriterien
|
||||
- [ ] `ssh-keygen -y -f` liest erzeugte Schlüssel (mit und ohne Passphrase)
|
||||
- [ ] Fingerprints identisch zu `ssh-keygen -lf`
|
||||
- [x] `ssh-keygen -y -f` liest erzeugte Schlüssel (mit und ohne Passphrase)
|
||||
- [x] 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-v1` statt `ssh-keygen`: keine Private Keys als Temp-Dateien.
|
||||
Die Tests prüfen gegen das echte `ssh-keygen` (beide Richtungen, mit/ohne Passphrase).
|
||||
- Passphrase: `aes256-ctr` + `bcrypt` mit **16 Runden** (ssh-keygen nimmt heute 24). `bcrypt-pbkdf`
|
||||
ist 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.com` via `ssh-keygen -Z`) werden mit klarer Meldung
|
||||
abgelehnt. Private-Key-Import nur für ed25519 und RSA.
|
||||
- `SchluesselFormatFehler` trägt einen `code` (`ungueltig`, `nicht_unterstuetzt`,
|
||||
`passphrase_fehlt`, `passphrase_falsch`, `zu_schwach`); Meldungen sind feste Sätze ohne Eingabe.
|
||||
- RSA-Mindestlänge 2048 Bit standardmäßig in `publicKeyZeileLesen` und `privateKeyLesen`;
|
||||
`{ rsaMindestBits: 0 }` für das reine Beobachten vorhandener `authorized_keys` (Drift).
|
||||
- Kommentare mit Steuerzeichen werden abgelehnt, sonst ließe sich über einen Kommentar eine zweite
|
||||
Zeile in `authorized_keys` einschleusen.
|
||||
- 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 – dort `chmod 400` und passenden Eigentümer setzen.
|
||||
- Schwärzen greift auf Feldnamen, die einen der Wortstämme `privat`, `passwort`, `password`,
|
||||
`passphrase`, `secret`, `geheimnis`, `token`, `masterkey`, `authorization`, `cookie` enthalten
|
||||
(nicht nur als Präfix), sowie auf PEM-Private-Keys in jeder Zeichenkette (auch abgeschnitten,
|
||||
auch in `message`/`stack` von Fehlern). Rohe Bytes werden zu `[Binärdaten]`.
|
||||
|
||||
Reference in New Issue
Block a user