Master-Key-Rotation
Für At-rest-Verschlüsselung
(Object-Storage-Verschlüsselung,
Durable-DD-Verschlüsselung) leben die Schlüssel des Frameworks in
einem MasterKeyRing — einer versionierten Map von Key-ID zu
Verschlüsselungsschlüssel. Rotation ist online: Neue Writes
laufen unter einer frischen Key-ID; alte Reads funktionieren weiter
unter dem Schlüssel, mit dem sie verschlüsselt wurden; ein
Hintergrund-Sweep verschlüsselt ältere Daten irgendwann neu.
import { MasterKeyRing } from 'actor-ts';
const keyRing = new MasterKeyRing({ keys: { 'k1': process.env.MASTER_KEY_V1!, 'k2': process.env.MASTER_KEY_V2!, // neu — aktuell }, currentKeyId: 'k2',});currentKeyId ist der Schlüssel, der für neue Writes genutzt
wird. Reads konsultieren keys, um den richtigen Schlüssel für die
jeweils gespeicherten Daten zu finden.
Wann rotieren
Abschnitt betitelt „Wann rotieren“Drei Auslöser:
- Geplante Rotation — eine Security-Policy (alle 90 Tage, jährlich).
- Vermutete Kompromittierung — geleaktes Schlüsselmaterial; sofort rotieren.
- Compliance — regulatorische Anforderungen schreiben periodische Rotation vor.
Auch ohne spezifischen Auslöser ist periodische Rotation gute Praxis — begrenzt den Blast Radius eines unentdeckten Leaks.
Der Rotations-Ablauf
Abschnitt betitelt „Der Rotations-Ablauf“ 1. Frischen Schlüssel erzeugen. Zu keyRing.keys hinzufügen; NOCH NICHT als currentKeyId promoten. 2. Den aktualisierten keyRing auf allen Nodes ausrollen. Verifizieren, dass Reads funktionieren — alte Daten nutzen weiter den alten Schlüssel, neue Daten weiter den vorherigen. 3. currentKeyId auf den neuen Schlüssel updaten. Ausrollen. Neue Writes nutzen den neuen Schlüssel. Alte Daten weiter lesbar. 4. Den Re-Encryption-Sweep laufen lassen. Alte Daten werden gelesen, entschlüsselt, mit dem neuen Schlüssel neu verschlüsselt. 5. Sobald der Sweep durch ist, den alten Schlüssel aus keyRing entfernen. Ein Rollback-Fenster von ~7 Tagen halten, in dem der alte Schlüssel noch verfügbar ist; danach droppen.Das Framework unterstützt jeden dieser Schritte ohne Downtime.
Schritt 1 — den neuen Schlüssel hinzufügen
Abschnitt betitelt „Schritt 1 — den neuen Schlüssel hinzufügen“const keyRing = new MasterKeyRing({ keys: { 'k1': process.env.MASTER_KEY_V1!, 'k2': process.env.MASTER_KEY_V2!, // neu }, currentKeyId: 'k1', // weiter v1 — v2 nur zum Ring hinzugefügt});Diese Config auf jeden Node ausrollen. Reads von v1-verschlüsselten Daten funktionieren weiter; Writes nutzen weiter v1.
Dieser Schritt ist sicher und umkehrbar — wenn v2 doch nicht
gebraucht wird, einfach aus keys entfernen.
Schritt 2 — den neuen Schlüssel promoten
Abschnitt betitelt „Schritt 2 — den neuen Schlüssel promoten“const keyRing = new MasterKeyRing({ keys: { 'k1': process.env.MASTER_KEY_V1!, 'k2': process.env.MASTER_KEY_V2!, }, currentKeyId: 'k2', // ← jetzt v2});Ausrollen. Neue Writes laufen unter v2. Reads konsultieren den keyRing und finden den richtigen Schlüssel (v1 oder v2) anhand des Key-ID-Headers der gespeicherten Daten.
Nach diesem Schritt sammeln sich neue Daten unter v2 an, sobald der Workload schreibt. Alte Daten bleiben unter v1, bis sie neu verschlüsselt werden.
Schritt 3 — Re-Encryption-Sweep
Abschnitt betitelt „Schritt 3 — Re-Encryption-Sweep“import { ReEncryptionSweep } from 'actor-ts';
const sweep = new ReEncryptionSweep({ store: snapshotStore, keyRing, targetKeyId: 'k2', batchSize: 100, rateLimit: 50, // Items pro Sekunde});
await sweep.run();Der Sweep läuft durch den Store, findet Items, die nicht unter
targetKeyId verschlüsselt sind, entschlüsselt + verschlüsselt neu.
Knöpfe:
batchSize— Items pro Batch.rateLimit— begrenzt die I/O-Rate, damit der Sweep das zugrundeliegende Storage nicht hämmert.filter— auf spezifische PersistenceIds beschränken (für partielle Rotation).
Der Sweep ist idempotent + wiederaufnehmbar — unterbrechen und neu starten greift dort wieder, wo aufgehört wurde. Tracked Fortschritt in den Metadaten des Stores.
Schritt 4 — den alten Schlüssel ausmustern
Abschnitt betitelt „Schritt 4 — den alten Schlüssel ausmustern“Nachdem der Sweep durch ist (jedes Item unter v2 verschlüsselt):
const keyRing = new MasterKeyRing({ keys: { 'k2': process.env.MASTER_KEY_V2!, }, currentKeyId: 'k2',});v1 komplett droppen. Daten, die weiter unter v1 verschlüsselt sind (z. B. Backups, die nicht neu verschlüsselt wurden), sind jetzt nicht mehr lesbar.
Warte ein Rollback-Fenster vor dem Droppen. ~7 Tage lassen dich davon erholen, falls “ach nein, der Sweep hat doch nicht alle Backups erfasst”. Nach bestätigter Migration v1 droppen.
Speicherung der Master-Keys
Abschnitt betitelt „Speicherung der Master-Keys“Der keyRing liefert kein Key-Storage-Backend mit. Übliche Muster:
| Quelle | Muster |
|---|---|
| Env-Vars | process.env.MASTER_KEY_V2 — einfachste Variante, fein für Tests. |
| K8s-Secrets | Als Files gemountet; beim Start gelesen. |
| HashiCorp Vault | Dynamisch beim Start ziehen; periodisch erneuern. |
| AWS KMS / GCP KMS / Azure Key Vault | Cloud-KMS-APIs. Decrypt-on-Load via die KMS-Encryption-Keys. |
Für Produktion ist KMS die richtige Antwort — Schlüssel verlassen die sichere Grenze nie im Klartext.
Multi-Cluster-Aspekte
Abschnitt betitelt „Multi-Cluster-Aspekte“Wenn mehrere Cluster denselben verschlüsselten Store teilen (z. B. eine DR-Replica, die die Backups der Primary liest), brauchen alle Cluster denselben keyRing. Gemeinsam rotieren; nicht zulassen, dass ein Cluster bei Schlüssel-Generationen zurückfällt.
Failure-Modes
Abschnitt betitelt „Failure-Modes“Wohin als nächstes
Abschnitt betitelt „Wohin als nächstes“- Object-Storage-Verschlüsselung — was die Master-Keys nutzt.
- Object-Storage-Key-Rotation — die Storage-seitigen Mechaniken.
- Cluster-Sicherheit — das In-Transit-Pendant zur At-rest-Verschlüsselung.
- Operations-Überblick — vollständige Security-Checkliste.