08 — Secrets Management
The security view of secrets (the platform mechanics are in platform/09, ADR-0030). The rule is absolute: no secret material in Git, images, logs, or IaC state — ever.
1. Secret inventory & handling
| Secret | Handling |
|---|---|
| App runtime (DB creds, provider keys, OIDC client secrets) | ESO ← cloud KMS/Vault; workload identity (no static creds) (ADR-0030) |
| API keys | hashed at rest (prefix-indexed, constant-time compare), shown once (02, ADR-0035) |
| Token signing keys (JWT) | KMS-backed, rotated, published via JWKS; verify kid |
| Encryption keys (DEK/KEK) | envelope, per-tenant, KMS, never exported (10) |
| TLS certificates | cert-manager + ACME (auto-issue/renew) |
| Webhook signing secrets | per-tenant, rotatable (product/08) |
| CI / cloud auth | OIDC, no long-lived keys (ADR-0032) |
| etcd Kubernetes Secrets | KMS encryption provider (defense in depth) |
2. Principles
- References in Git, material in a manager —
ExternalSecret/SecretStoreare safe to commit; values live in the KMS/vault and sync to the cluster (platform/09). - Workload identity over static credentials wherever the runtime supports it — there’s nothing to leak.
- Least privilege + per-env stores/keys — a nonprod compromise can’t read prod secrets.
- No secret in transit through query strings or logs (CWE-532).
3. API-key storage (a frequent footgun)
API keys are high-entropy, so: store only a hash (the public prefix/keyid indexes the row; verify the secret by hashing + constant-time compare), display once, and support rotation (overlap window) + instant revocation. A database dump of the keys table yields no usable keys. Leak detection: secret scanning in CI + Git push protection (platform/07).
4. Rotation, leak response, and break-glass
- Rotation: automated for managed secrets (ESO re-sync), scheduled for signing/ encryption keys (JWKS/KMS rotation), overlap windows to avoid downtime.
- Leak response: secret scanning → auto-revoke + rotate + audit; documented runbook.
- Break-glass: emergency elevated access is time-boxed, MFA-gated, dual-controlled, and heavily audited (07) — never a standing god-credential.
5. Threats addressed & residual
| Threat | Control | Residual |
|---|---|---|
| Secret in Git/image/log | ESO refs + scanning + no-plaintext rule | low |
| Stolen DB → usable API keys | hashing at rest | very low |
| Static-credential theft | workload identity (none to steal) | very low |
| Signing-key compromise | KMS-backed + rotation + kid validation |
low |
| Standing privileged creds | break-glass only (time-boxed, audited) | low |
References
- External Secrets Operator: https://external-secrets.io/
- OWASP Secrets Management Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
- CWE-798 (hard-coded creds): https://cwe.mitre.org/data/definitions/798.html