Expand description
Envelope encryption for tenant LLM provider keys (BYOK).
§Why this lives in the edge
A tenant’s OpenAI/Anthropic key is the most sensitive value the platform handles: it bills to their account and it is useful to an attacker on its own. The design goal is that plaintext exists only in this process.
- Brain never sees it. The engine holds a namespace-scoped grant and calls the edge, which swaps the grant for the real key on the way upstream. A Brain compromise — WAL, snapshots, backups — yields no provider keys, because none were ever written there.
- The store never sees it.
SealedSecretis the only shape that crosses thecrate::port::LlmCredentialStoreboundary. Whatever persists it — Postgres in the hosted gateway, a file in self-host — holds ciphertext and nothing else, so a database compromise yields nothing usable without the key-encryption key, which lives in this process’s configuration and never in its data.
§The construction
AEAD (ChaCha20-Poly1305) under a key-encryption key, with a fresh random 96-bit nonce per seal and the binding context as additional authenticated data.
The AAD is load-bearing, not decoration. It binds the ciphertext to the
namespace and provider it was sealed for, so a stolen row cannot be replayed
under a different tenant: moving acme’s ciphertext into globex’s row
makes the tag fail and the open returns an error rather than another
tenant’s key. Without it, a store with row-level write access would be a
cross-tenant key-swap primitive.
kek_id is carried in the clear beside the ciphertext so several KEKs can
coexist. That is what makes rotation possible without a flag day: a new KEK
is added, new seals use it, and old rows stay readable until re-sealed.
§Why ring
ring is already in this binary’s dependency tree (via rustls), so using it
adds no new cryptographic implementation to audit. The alternative —
pulling a second AEAD crate — would widen the trusted surface to save
nothing.
Structs§
- KeyRing
- A set of key-encryption keys, one of them current.
- Sealed
Secret - An encrypted secret, exactly as it is persisted.
- Secret
Binding - The context a ciphertext is bound to.
Enums§
- Crypto
Error - What can go wrong sealing or opening a secret.
Constants§
- KEK_
CURRENT_ ENV - Env var naming which KEK id new seals use.
- KEK_LEN
- Length of a raw key-encryption key, in bytes.
- KEK_
SPEC_ ENV - Env var holding the key-encryption keys, as
id:hex,id:hex,….
Functions§
- keyring_
from_ env - Build the key ring from the environment, or
Nonewhen BYOK is not configured.