Concept

KMS and secrets

Per-merchant credentials are encrypted at rest with AWS KMS. Understand the model, the local-dev bypass, and the operational failure modes.

Breeze Buddy stores per-merchant telephony and STT/TTS credentials in Postgres. Each credential value is encrypted with AWS KMS before insertion and decrypted on read. The app-level credentials in .env (Azure OpenAI, Daily, default ElevenLabs) are not KMS-wrapped — those are read directly from the process environment.

Developers: this is automatic

Per-merchant credential isolation and KMS wrapping are part of Breeze Buddy’s managed infra — as a developer you just reference credentials by ID in your templates (or let the platform resolve them from the lead’s reseller/merchant scope) and the runtime decrypts on the fly. This page is for operators configuring the multi-tenant vault.

Two classes of secret

ClassExampleWhere it livesEncryption
App-levelAZURE_OPENAI_API_KEY, DAILY_API_KEY, JWT_SECRET_KEYProcess envNot wrapped — your secrets manager is responsible.
Per-merchantA merchant’s Twilio account SID, a merchant’s Sarvam keyPostgres, encryptedKMS-wrapped on write; decrypted on read.

The per-merchant wrapping is what makes multi-tenant key isolation cheap. Rotating a merchant’s Twilio key is a single DB update; it has no effect on any other merchant.

The decrypt path

On every request that needs a merchant credential:

  1. Load the encrypted blob from Postgres.
  2. Call KMS Decrypt using AWS_REGION + the configured access key.
  3. Cache the plaintext in memory for the duration of the call.
  4. Use the plaintext to call the merchant’s upstream provider.

The cache is per-process, never written to disk, and evicted when the call ends.

Required env

VarPurpose
AWS_REGIONRegion your KMS key lives in.
AWS_ACCESS_KEY_IDAccess key with kms:Decrypt permission on the merchant key.
AWS_SECRET_ACCESS_KEYMatching secret.
SKIP_KMS_DECRYPTfalse in production. true only for local dev (see below).

The local-dev bypass

Setting SKIP_KMS_DECRYPT=true tells Breeze Buddy to treat the value in Postgres as plaintext — no KMS call. This lets you insert a merchant’s Twilio SID directly during local development without AWS creds.

Never in production

SKIP_KMS_DECRYPT=true disables encryption-at-rest for per-merchant credentials. Production secrets leak to disk at insertion time. Enforce at the secrets-manager / deployment config layer that this var is never true in production.

Failure modes

  • KMS region mismatch — decrypt fails with a region error. Verify AWS_REGION matches the key’s region.
  • IAM permission missing — decrypt fails with AccessDenied. Grant kms:Decrypt on the merchant key’s ARN.
  • KMS rate limits — at high call volume, you may hit per-second decrypt quotas. Monitor ThrottlingException in logs and request a quota increase.
  • Credential rotation — rotating the app-level AWS creds without propagation means all calls using per-merchant credentials fail. Stage rotations carefully.
  • Key deletion / disable — disabling the KMS key immediately breaks all merchant operations. Do not disable keys as part of routine cleanup.

JWT signing keys

JWT_SECRET_KEY signs user access tokens. It is app-level, not per-merchant. Rotating it invalidates every outstanding access token — users and integrations must re-auth. Document the rotation procedure in your incident-response runbook before you need it.

Next steps

Was this helpful?