External Secrets¶
External secrets are centralized credentials for third-party providers (OpenAI, Stripe, GitHub, SendGrid, …) that PaaS Runtime stores encrypted and auto-injects into your apps as environment variables. You manage them once and every deploy picks them up — no copy-pasting API keys into each app's config.
Why¶
- Encrypted at rest — values are sealed with AES-256-GCM; the API never returns a stored value (list/read endpoints are metadata-only).
- One source of truth — set a provider key once at the tenant level and all your apps inherit it.
- Per-app overrides — an individual app can override the tenant default for a given provider key when it needs a different credential.
Scopes¶
| Scope | Set where | Applies to |
|---|---|---|
| Tenant default | Settings → External Secrets (/settings/secrets) |
every app in the tenant |
| App override | an app's External Secrets tab (/apps/{id}/external-secrets) |
that app only (wins over the tenant default for the same provider + key) |
The app view shows a merged list: each row is badged App-specific (🔵, an override you can edit/delete here) or Inherited (⚫, the tenant default — read-only here, managed in Settings).
Providers & keys¶
A catalog of 50 providers is available. Each provider declares the keys it
needs (e.g. OPENAI_API_KEY) and, where supported, a Test action that
makes a real call to verify the credential. Stored secrets can also be
rotated in place.
Lifecycle (how it was built)¶
The feature shipped across phases: tenant-scoped CRUD + encryption + test +
rotate, per-app overrides, the dashboard UIs, and a server-side merged
endpoint. Each privileged action emits a distinct audit event
(external_secret.created, .rotated, .deleted, .injected, .accessed,
.test_passed, .test_failed, .app_scoped, .merged_fetched, plus
external_secret.provider_lookup) so the full credential lifecycle is
traceable.
Injection¶
See External Secrets Injection for how a secret reaches a running pod's environment at deploy time.