Secrets & tenancy, by construction

Letting agents operate production is a trust problem before it is an engineering one. So we built the safety architecture first — and this is exactly how it works.

where secrets live

Four kinds of secret. Four homes.

The rule of thumb: anything that belongs to a customer lives in the customer's own AWS account. Lemma's control plane holds only its own operational secrets.

KindExampleWhere it livesWho can read it
Control-plane configour DB password, the model API key, signing keysAWS Secrets Manager in Lemma's accountcontrol-plane tasks only
Control-plane row-levela user's TOTP seed, an OIDC client secretFernet ciphertext in Lemma's Postgresdecrypted in-process
Customer infraRDS master password, Redis authSecrets Manager in the customer's accountthe customer's own infra
Customer app envthe app's DATABASE_URL, STRIPE_KEYa JSON secret in the customer's accountwrite-only to Lemma
customer app secrets

Write-only, start to finish

The app's own secrets are detected, set by the customer, and injected into the container — without ever touching Lemma's database, logs, or agent transcripts.

01

Detect

A deploy reads the app's .env.example and declares the variable names it needs. Platform-provided names (DATABASE_URL, PORT) are dropped — Lemma injects those itself.

02

Wait

The deploy parks on a checklist card until every declared key is set or explicitly skipped. The pipeline visibly waits on you — nothing ships half-configured.

03

Set — masked

You enter values in a masked form. They're written into a single JSON secret in your own account's Secrets Manager. Lemma's database records only the key name, who set it, and when — never the value.

04

Inject per-key

At container launch each variable is delivered individually from your Secrets Manager via ECS ValueFrom. The value never passes through Lemma's application code.

Because chat transcripts persist, agents only ever see secret names, never values — and the product will never ask for a secret in chat.

least privilege

Safe by construction

Read-only data queries

When the Data agent queries a customer database, it runs inside the customer's own network as a dedicated read-only role, in a read-only transaction with a statement timeout and row cap. It's off by default — the workspace owner opts in. No write path exists.

Rotatable encryption

Row-level secrets are encrypted with a Fernet key-ring, newest-first. Rotation is zero-downtime: add a key, re-encrypt, drop the old one — no reads break. Signing keys rotate the same way.

Production fail-fast

A hosted environment refuses to boot on a weak, empty, or placeholder key — for signing or encryption. Un-populated secrets fail loudly instead of silently running a default.

the road to SOC 2

The same architecture gets us compliant

Tenant isolation, an audit trail on every agent action, and identity controls aren't a later retrofit — most of it is already in the codebase.

  • Cross-tenant isolation, enforced at the data layer
  • Audit trail on every agent action + approval
  • MFA (TOTP) and OIDC single sign-on
  • Failed-login lockout + idle session timeout
  • Enforced spend caps — the bill cannot run away
  • Owner-gated approvals for every money-moving action

Deep-dive documentation available to design partners on request.