Zum Inhalt springen
Deutsch

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.

Drei Auslöser:

  1. Geplante Rotation — eine Security-Policy (alle 90 Tage, jährlich).
  2. Vermutete Kompromittierung — geleaktes Schlüsselmaterial; sofort rotieren.
  3. Compliance — regulatorische Anforderungen schreiben periodische Rotation vor.

Auch ohne spezifischen Auslöser ist periodische Rotation gute Praxis — begrenzt den Blast Radius eines unentdeckten Leaks.

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.

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.

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.

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.

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.

Der keyRing liefert kein Key-Storage-Backend mit. Übliche Muster:

QuelleMuster
Env-Varsprocess.env.MASTER_KEY_V2 — einfachste Variante, fein für Tests.
K8s-SecretsAls Files gemountet; beim Start gelesen.
HashiCorp VaultDynamisch beim Start ziehen; periodisch erneuern.
AWS KMS / GCP KMS / Azure Key VaultCloud-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.

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.