Size / Priority
- Size: L — touches encryption infrastructure.
Rationale
Current encryption (src/persistence/object-storage/Encryption.ts) uses a single bucket-wide master key. All entity state encrypted with the same key family.
Stronger model: per-entity envelope encryption:
- Each entity has a unique Data Encryption Key (DEK).
- DEKs wrapped by the master Key Encryption Key (KEK).
- KEK rotation: rewrap DEKs; entity state unchanged.
Benefits:
- KEK rotation faster (only DEK wrappers change; entity payloads stay).
- Smaller blast radius (DEK leak ≠ master-key leak).
- Per-tenant key isolation if DEK is per-tenant.
Design sketch
// src/persistence/encryption/EnvelopeEncryption.ts (new)
export interface EnvelopeEncryptionConfig {
readonly kek: KeyEncryptionKey; // master, rotatable
readonly dekStore: DekStore; // where wrapped DEKs live
}
export interface KeyEncryptionKey {
readonly id: string;
wrap(dek: Uint8Array): Promise<Uint8Array>;
unwrap(wrappedDek: Uint8Array): Promise<Uint8Array>;
}
export interface DekStore {
load(persistenceId: string): Promise<{ wrapped: Uint8Array; kekId: string } | undefined>;
save(persistenceId: string, wrapped: Uint8Array, kekId: string): Promise<void>;
}
// PersistentActor opts in:
class MyActor extends PersistentActor<...> {
override encryptionConfig(): EncryptionConfig {
return { mode: 'envelope', envelope: this.system.extension(EnvelopeEncryptionId) };
}
}
KEK rotation: rewrap all DEKs (sweep similar to existing master-key sweep).
Integration
Out of scope / non-goals
- HSM integration — pluggable via KEK interface; user provides HSM-backed KEK.
- Per-record DEK (each event has its own) — phase 1 per-entity only.
Open design questions
- DEK storage: alongside journal vs separate store. Recommend separate (
DekStore interface).
- First-write DEK generation: when does the DEK first get created? On first persist. Document.
- Old-DEK retention during rotation: keep until sweep complete.
Test plan
- Encrypt event with per-entity DEK; decrypt round-trip.
- KEK rotation: rewrap; old entities still decrypt.
- DEK leak doesn't compromise other entities.
- Per-tenant DEK scoping.
Acceptance criteria
Pre-implementation checklist
Size / Priority
Rationale
Current encryption (
src/persistence/object-storage/Encryption.ts) uses a single bucket-wide master key. All entity state encrypted with the same key family.Stronger model: per-entity envelope encryption:
Benefits:
Design sketch
KEK rotation: rewrap all DEKs (sweep similar to existing master-key sweep).
Integration
Out of scope / non-goals
Open design questions
DekStoreinterface).Test plan
Acceptance criteria
EnvelopeEncryption+ KEK/DEK interfaces.Pre-implementation checklist