Key Vault (control plane)
Owns key lifecycle, the PII registry, the deletion state machine, and certificate signing. A REST API backed by a document store for keys/metadata and a warehouse table for lineage and audit history.
Chameleon is a compliance control plane built around crypto-shredding: every user gets one encryption key, all their PII is encrypted with it, and deleting that key makes every copy of their data — wherever it ended up — unreadable, instantly, everywhere. This page covers how the system is put together and why that design holds up.
Chameleon splits cleanly into two responsibilities. The control plane owns per-user encryption keys, the PII registry (what's declared where), the deletion lifecycle, and the signed certificates that prove deletion happened. It never handles bulk data — only keys and metadata.
The data plane does the heavy lifting: it fetches a user's encryption context from the control plane, encrypts PII at ingestion, and keeps a central encrypted vault table in sync with every declared source. It never makes deletion decisions — it only asks the control plane for a key, and later respects that the key is gone.
Your own console or application never talks to the control plane directly — it goes through a thin server-side proxy, which is where session auth and request forwarding live, keeping key-management credentials out of anything that runs in a browser.
Key Vault (control plane)
Owns key lifecycle, the PII registry, the deletion state machine, and certificate signing. A REST API backed by a document store for keys/metadata and a warehouse table for lineage and audit history.
Data pipeline (data plane)
Encrypts PII on ingestion using a key fetched from the control plane, and runs the sync job that keeps the encrypted vault table current for every declared resource.
Console
The customer-facing UI: declares resources, triggers deletions, renders decrypted values on demand. A browser-facing proxy — it holds no keys and never talks to the control plane's API directly from client code.
| Scheme | Used by | Properties |
|---|---|---|
| Deterministic AES-256-GCM | Legacy direct encrypt/decrypt API calls | Same plaintext always encrypts identically for a given user (IV derived from the user's identity). Enables joins and dedup on ciphertext, at the cost of weaker pattern-analysis resistance within one user's data. |
| Randomized AES-256-GCM | The vault-backed path used everywhere else — on-demand decrypt, decrypted views, ingestion | A fresh random IV per encryption, so identical plaintext never produces identical ciphertext. This is the scheme real ingested PII actually uses; the control plane only decrypts it on read, it never performs this encryption itself. |
One key per user
Every user has exactly one 32-byte encryption key. Every piece of their PII, wherever it's declared — a warehouse table, a dbt model, a connected SaaS export — is encrypted with that same key. "Deleting a user" means destroying that one key. There is no row-by-row deletion to get wrong, and no copy left readable anywhere, because nothing can decrypt without a key that no longer exists.
{
"userId": "usr_8f2a1c",
"keyVersionId": "v1",
"wrappedDek": "<base64-encoded, key-wrapped DEK>",
"algorithm": "AES-256-GCM",
"encryptionVersion": 2,
"tokenization": {
"algorithm": "HMAC-SHA256",
"tokenKeyId": "tok_v1"
}
}A simplified walk from declaring a resource to a signed proof of deletion — each step is covered in depth in its own upcoming doc.
A resource — a warehouse table, a dbt model, a connected SaaS object — gets declared to the PII registry, either manually, via the dbt package, or through automatic discovery.
The data plane fetches each user's encryption context from the control plane and encrypts declared PII fields before they land in the central vault.
The control plane never stores plaintext or bulk data — only the per-user key material and the registry/lineage metadata describing what's protected and where.
When your console needs to show a real value, it asks the control plane to decrypt on demand — plaintext is produced only for that single response, never persisted as a standing copy.
Deleting a user destroys their key. Every encrypted copy, in every declared location, becomes permanently unreadable in the same instant — and a signed certificate documents that it happened.
Does Chameleon ever see my data unencrypted?
Only transiently, and only when explicitly asked. Encryption happens in the data plane at ingestion using a key it fetches per-request; plaintext is produced again only on an explicit decrypt call, for that single response, and is never written to a standing store. At rest, everything in the vault is ciphertext.
What's the difference between the two encryption schemes described above?
Deterministic AES-256-GCM (legacy direct API only) always produces the same ciphertext for the same plaintext and user, which is convenient for joins but weaker against pattern analysis. Randomized AES-256-GCM — the scheme real ingested PII actually uses — uses a fresh random IV every time, so identical values never look identical in storage.
Is self-hosting Chameleon possible?
Yes — Chameleon supports a bring-your-own-cloud (BYOC) deployment where the entire control plane and data plane run inside your own cloud project, with no runtime dependency on Chameleon's infrastructure afterward. A dedicated self-hosting guide is coming to this docs section soon.
All available developer documentation.
How Chameleon maps where personal data lives across your warehouse.
A plain-language look at why destroying a key beats scanning and deleting rows.