PII Gate
Overview
Section titled “Overview”The PII Gate intercepts fields marked #[pii] before they are written to the WAL and replaces them with envelope-encrypted ciphertext. The plaintext never appears in the event log or in audit bundles — only the encrypted form is stored.
This allows you to:
- Comply with GDPR right-to-erasure by deleting the data encryption key (DEK), rendering all encrypted PII unreadable without modifying the log
- Limit blast radius if the event log is exfiltrated
- Selectively decrypt PII for authorized parties without exposing it broadly
Marking fields as PII
Section titled “Marking fields as PII”#[table(name = "patient_records")]pub struct PatientRecord { #[primary_key] pub id: u64, #[pii(key_context = "patient")] pub name: String, #[pii(key_context = "patient")] pub date_of_birth: String, #[pii(key_context = "patient")] pub ssn: String, pub diagnosis_code: String, // not PII — stored plaintext}The key_context groups fields under a shared DEK. Deleting the DEK for "patient" renders all name, date_of_birth, and ssn fields unreadable.
Encryption scheme
Section titled “Encryption scheme”| Property | Value |
|---|---|
| Algorithm | AES-256-GCM (envelope encryption) |
| DEK generation | Random 256-bit key per key_context |
| DEK storage | Encrypted under the node’s master key (or KMS) |
| Nonce | Random 96-bit nonce per field value |
Decryption
Section titled “Decryption”Authorized reducers and queries can decrypt PII:
#[reducer]#[requires_capability("pii:read")]pub fn get_patient_record(ctx: &ReducerContext, patient_id: u64) -> PatientRecord { let record = PatientRecord::filter_by_id(&patient_id).unwrap(); // record.name is automatically decrypted for this reducer record}PII fields are only decrypted in the context of a reducer or query that declares the pii:read capability. Subscription deltas do not include decrypted PII unless the subscribing identity has pii:read.
GDPR right-to-erasure
Section titled “GDPR right-to-erasure”To erase a patient’s PII:
cosmictron-cli pii erase --key-context patient --context-id 12345This:
- Deletes the DEK for
patient:12345 - All events containing
name,date_of_birth,ssnfor that patient become permanently unreadable (the ciphertext remains but cannot be decrypted) - The erasure operation itself is logged in the event log
KMS integration
Section titled “KMS integration”In production, DEKs should be protected by an external KMS:
[compliance.pii]kms_provider = "aws"kms_key_id = "arn:aws:kms:us-east-1:123456789:key/abcd-1234"Supported KMS providers: AWS KMS, HashiCorp Vault, Google Cloud KMS.