Docs/Decisions/ADR-0010 Secret Injection Model

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/.env for 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

How this maps to self-hosting

ComposeHelm
StoreUntracked 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)
RotationEdit .env, recreate the consumersUpdate the Secret, restart the consumers (or use an external-secrets operator)
BackupBack 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