Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Encryption at rest

Sensitive payloads are sealed under a per-tenant envelope before being written to storage, rather than relying solely on a provider’s default storage-level encryption. The design goal: even with access to the raw table, one tenant’s plaintext should never be recoverable using another tenant’s key material or context.

Envelope model

  • A shared root key (customer-managed) wraps a per-write data key.
  • The tenant is bound into the envelope as encryption context/AAD: a ciphertext sealed for tenant A cryptographically cannot be opened using tenant B’s context, even under the same root key. This is a second, independent tenant boundary layered under the application-level checks described in Isolation model — a defense-in-depth property, not a replacement for them.
  • Ciphertext is framed with a version byte so the format itself is versioned and can evolve without breaking old records.

What is covered today

  • Connector configs (config_enc) — a connector binding’s config, which may carry an API key, bearer token or basic-auth password, is sealed before being persisted. Only config (plaintext) exists for bindings created before encryption was enabled; readers accept both (config_enc preferred, config as a compatibility fallback) so older bindings keep working, and can be re-sealed on their next update.
  • Fail-closed behavior: if a stored value indicates it should be encrypted but the decrypting process has no key access configured, the read fails rather than silently returning ciphertext or skipping decryption.

What is not yet covered

Execution and human-task payloads (input/output/form data flowing through workflow runs) currently rely on the storage provider’s own default encryption rather than the per-tenant envelope above. Bringing these under the same tenant-bound envelope — either at the storage layer or per-attribute before write — is tracked as a follow-up; until then, treat workflow input/output as not cryptographically tenant-isolated beyond the application-level checks in Isolation model.

Practical implication for connector configs

Because a connector config is encrypted at rest, GET /connectors returns the config as the worker will use it (decrypted, for the caller’s own tenant) — the ciphertext form is never exposed over the API. A secret placed in a connector config is protected from anyone with read access to the raw database, but is still visible to any authenticated member of the tenant via the API — connector config secrets are a tenant-shared credential, not a per-user one.