External Secrets Injection¶
This page explains how a stored external secret reaches a running app's environment, and how to verify it.
Mechanics¶
At deploy time the control-plane resolves the secrets that apply to the app
(app-specific overrides + inherited tenant defaults, app wins per provider+key),
decrypts them, and materializes a Kubernetes Secret named
app-{app_id}-external-secrets in the app's namespace. The app's Deployment
references that Secret via envFrom (optional: true), so each provider key
becomes an environment variable in the pod — and if the app has no external
secrets, the reference is a harmless no-op.
secret stored (encrypted)
│ deploy
▼
control-plane: resolve + decrypt + Patch::Apply
▼
K8s Secret app-{app_id}-external-secrets
▼ envFrom (optional: true)
pod env: OPENAI_API_KEY=…
The injection is best-effort: a missing master key or empty secret set never fails the user-visible deploy — the pod simply starts without those vars.
Set it up¶
- Add the credential — tenant-wide in Settings → External Secrets, or app-specific on the app's External Secrets tab.
- Deploy the app (
POST /v1/apps/{id}/deploys, or push/redeploy as usual). - The new pod boots with the provider keys in its environment.
Deploy API contract¶
The injection runs as part of the deploy. POST /v1/apps/{id}/deploys must
include tenant_id (and app_id) in the request body — the injection hook
resolves the secrets from body.tenant_id:
Empty tenant_id silently skips injection
A deploy whose body omits tenant_id (e.g. only image_ref) resolves
secrets for an empty tenant → zero rows, no Secret materialised, no
external_secret.injected event. The deploy itself still succeeds (the
pod just starts without the provider keys). Always send tenant_id.
The dashboard and CLI populate it for you; only hand-crafted API calls
are at risk.
Verify¶
# inspect the materialized Secret
kubectl -n paas-apps get secret app-<app_id>-external-secrets -o yaml
# confirm the var is present in the running pod
kubectl -n paas-apps exec deploy/<app> -- env | grep OPENAI_API_KEY
A successful injection emits an external_secret.injected audit event
(paas_audit_events), carrying the app id and the number of keys injected.
Troubleshooting¶
| Symptom | Likely cause |
|---|---|
| var absent from pod env | no external secret set for the tenant/app, or the deploy predates adding it → redeploy |
| Secret object missing | injection skipped (no secrets, or master key unset) — check control-plane logs |
| wrong value injected | an app override exists — check the app's External Secrets tab (app wins over tenant default) |