ADR-0010: Secrets reach services as environment, from one source of truth
- Status
- accepted
- Decided
- September 2026 (first for the hosted deployment)
- Applies to this repository
- Yes, with a different store:
deploy/compose/.envfor Compose, Kubernetes Secrets for Helm. The original hosted deployment kept secrets in Azure Key Vault, referenced by its container platform; that setup is not part of this repository.
Context
Core and the satellite services read every secret from environment variables
(APP_ENCRYPTION_KEY, POSTGRES_PASSWORD, KEYCLOAK_CLIENT_SECRET,
SIDECAR_SHARED_SECRET, …). Tenant credentials (LLM provider keys, channel
secrets) are not environment variables: they are entered in the console and stored
encrypted with APP_ENCRYPTION_KEY. When the hosted deployment moved hosts,
APP_ENCRYPTION_KEY had to be carried over by hand; a regenerated key would have
made every stored credential undecryptable.
Decision
- One source of truth per deployment, read by every process that needs the value. Generated once, never regenerated.
- Least privilege: each service receives only the secrets it uses; shared secrets (for example
SIDECAR_SHARED_SECRET) are identical on both ends. - Values never in documents, commits or logs; refer to names.
How this maps to self-hosting
| Compose | Helm | |
|---|---|---|
| Store | Untracked deploy/compose/.env, generated by scripts/vegaduta secrets (random values; existing values never overwritten) | Kubernetes Secrets; global.core.appSecret.existingSecret holds APP_ENCRYPTION_KEY for core, core-jobs, core-worker and the migrate Job ("" = generated once by helm install) |
| Rotation | Edit .env, recreate the consumers | Update the Secret, restart the consumers (or use an external-secrets operator) |
| Backup | Back up the secret store together with the database. APP_ENCRYPTION_KEY cannot be rotated like the others: rotation needs a decrypt/re-encrypt migration (APP_ENCRYPTION_KEY_PREVIOUS covers the window). | |
Evidence & references
deploy/compose/.env.example,scripts/vegaduta(secrets),deploy/helm/charts/vegaduta/values.yaml(global.core.appSecret).- Secrets & Key Management.