Skip to content

Keys & encryption

KeyProtectsLivesRotation
Vault master key (VAULT_MASTER_KEY, 32-byte AES)Every artifact’s data key — effectively the whole vaultDeployment secret store (Railway variable in the reference deployment); ideally KMS or hardware tokenRe-wrap procedure below
Per-artifact data keys (AES-256-GCM)One artifact eachOnly in wrapped form, in the databaseNever rotated — destroyed on erasure
Attestation signing key (Ed25519)Authenticity of attestationsPEM on the persistent volume (ATTESTATION_PRIVATE_KEY_PATH)Generate new; dual-publish public keys during transition
Webhook signing key (WEBHOOK_SIGNING_KEY)Webhook authenticityDeployment secret store; shared with consumers out-of-bandIssue new, run dual-verify window on consumers, retire old
API keys (BAQSHI_API_KEYS)The whole backend APIDeployment secret store (comma-separated list)Append new key → migrate callers → remove old (zero downtime)
Handoff tokensOne capture flow eachDatabase rowsSelf-expire in 30 min; revocable per row

Back up the vault master key somewhere the deployment platform is not. A password manager entry or a sealed offline note. This is deliberate: losing it destroys the vault (that’s what makes erasure trustworthy) — so treat it with the same care as the data itself. Never commit it; never log it.

Blobs never need re-encrypting — only the small wrapped keys do:

  1. Generate a new 32-byte key; keep both old and new available.
  2. For each artifact row: unwrap the data key with the old master, re-wrap with the new, update the row (a short script inside a transaction; the vault blobs are untouched).
  3. Swap VAULT_MASTER_KEY to the new value, restart, verify a random sample of artifacts decrypts.
  4. Destroy the old key.

Rotate on: personnel change with key access, any suspicion of exposure, or a calendar cadence you set (annual is a sane default).

  • Cipher: AES-256-GCM, 12-byte random nonce per operation, nonce prepended to ciphertext.
  • AAD: artifact encryption binds the verification ID; key-wrapping binds a fixed context string — cross-record replay fails authentication.
  • Hashing: SHA-256 for artifact integrity (plaintext hash stored), audit chaining, and API-key fingerprints.
  • Signatures: Ed25519 (attestations), HMAC-SHA256 (webhooks).
  • Randomness: all keys/nonces/tokens from the OS CSPRNG.
  • Dev fallback: without a configured master key, a local one is generated and file-persisted (0600) so development works — production must always set VAULT_MASTER_KEY explicitly.