Encryption at rest & in transit
Encryption in Veil Keys is built on named, standard primitives — not bespoke cryptography. The goal is simple to state: a stolen database is worthless, and nothing sensitive travels in the clear. This page describes the model and the guarantees, not the implementation.
At rest: AES-256-GCM with envelope encryption
Every sensitive value — credential plaintext, connection strings, OAuth tokens, SSH private keys — is encrypted before it touches storage using AES-256-GCM, an authenticated cipher that protects both confidentiality and integrity (a tampered ciphertext fails to decrypt rather than decrypting to garbage).
Rather than one master key guarding everything, Veil Keys uses envelope encryption with a two-level key hierarchy:
- Per-workspace data-encryption keys (DEKs). Each workspace has its own DEK. A secret in one workspace is encrypted under a key that has nothing to do with any other workspace’s key.
- A root key wraps every DEK. DEKs are themselves stored encrypted (wrapped) under a root key. The root key is KMS-swappable — it can live in a key-management service and be rotated or replaced without re-encrypting your data.
- The database stores only ciphertext and wrapped keys. There is no column anywhere that holds a plaintext secret. A database dump yields ciphertext plus wrapped keys, and neither is usable on its own.
Why per-workspace keys matter
| Property | What it buys you |
|---|---|
| Blast-radius containment | A problem with one workspace’s key does not extend to others. |
| Independent rotation | Rotate a single workspace’s DEK without disturbing the rest. |
| Root-key portability | Swap or rotate the root (e.g. move to a managed KMS) without re-encrypting stored secrets. |
| Clean tenant boundaries | Encryption boundaries line up with the access-control boundaries in Access control. |
In transit: TLS 1.3 everywhere
Every connection — app to API, CI to API, agent broker to upstream — is protected with TLS 1.3. That means modern cipher suites, forward secrecy, and a reduced handshake with no legacy downgrade paths. Secrets that are decrypted transiently for injection travel onward to their bound upstream over TLS as well; see Domain binding for how the destination is pinned.
Tokens are stored hashed, never in plaintext
Agent, CI, and SSH tokens authenticate non-human clients. Veil Keys stores only a SHA-256 hash of each token — never the token itself. The full token value is shown once, at creation, and cannot be retrieved afterward. A leaked database reveals hashes, not usable credentials, and a token can be revoked the moment it’s suspected.
Secrets never appear in logs
Plaintext is excluded from logs by design — request logs, error traces, and the audit trail all record that a secret was used and the metadata of the action, never the value. The plaintext exists only transiently in the broker’s memory at the moment of injection.
Summary
| Layer | Primitive | Guarantee |
|---|---|---|
| Secrets at rest | AES-256-GCM, envelope encryption, per-workspace DEKs wrapped by a KMS-swappable root | A database dump yields only ciphertext; no single key decrypts everything; keys rotate independently |
| In transit | TLS 1.3 | Forward-secret, modern transport with no downgrade |
| Tokens | SHA-256 hash at rest, shown once | A leaked database holds no usable tokens |
| Logs | Plaintext excluded | Secrets never persist in logs or traces |