CoursesAdvanced secrets managementArchitecture & threat model

The secrets threat model & secret-zero

Sprawl, standing privilege, blast radius, and the bootstrap-trust problem.

Advanced35 min · lesson 1 of 15

Advanced secrets management starts with a threat model, not a tool. Before you reach for Vault or a cloud secrets manager, you have to be able to answer three questions precisely: what counts as a secret, every place a given secret comes to rest or passes through, and who the adversary is at each of those places. Most breaches are not broken cryptography — they are a secret sitting somewhere nobody was defending, read by an identity nobody was scoping. The whole discipline is shrinking the set of places secrets live and the window in which any one of them is valid.

The four states every secret passes through

A secret is exposed differently in each of four states, and a real design defends all four. At rest it lives in storage — etcd, a state file, a backup, a KMS. In transit it crosses the network — hopefully inside TLS, but often also inside a CI log or an error message. In use it is decrypted in process memory, readable by anything that can inspect the process. And in the audit trail it leaves a record of who read it and when — which is itself sensitive. Defending only "at rest" (the part encryption products advertise) leaves the other three wide open.

Where secrets actually leak — by location
source & pipeline
git history
committed once = leaked forever
CI logs & env
echoed, cached, printed on error
container image layers
baked-in build args
runtime & platform
process env / /proc
any local read sees it
etcd / K8s Secret
base64, not encryption
crash dumps & core files
memory hits disk
storage & ops
backups & snapshots
often unencrypted, long-lived
log aggregation
secrets in stack traces
developer laptops
.env, shell history, IDE cache
The secrets manager guards one box. The program is to make sure the secret never rests in any of the others.

Sprawl, standing privilege, and blast radius

Three properties predict how bad a leak will be. Sprawl is the number of independent copies of a secret — every copy is an attack surface and a thing you must find and rotate. Standing privilege is how long a credential stays valid and how much it can do while nobody is using it; a database password that is valid for a year and grants full access has enormous standing privilege. Blast radius is what one compromised secret unlocks — a scoped, read-only, one-database credential has a small radius; a shared "app" password reused across services has a huge one.

In plain terms
A static shared password is like one master key copied for every employee: you cannot tell who used it, you cannot revoke one copy, and re-keying the building means re-keying everyone at once. Dynamic, per-workload, short-lived credentials are like badges that expire at midnight and are printed per person — losing one is a shrug, not a fire drill.

Secret-zero: the bootstrap-trust problem

Every secrets system has a chicken-and-egg problem at the very start: to fetch secrets, a workload must first authenticate to the secrets manager — but authenticating requires a credential, which is itself a secret. That first credential is "secret-zero." If you solve it by shipping a static token in an environment variable or a Kubernetes Secret, you have not removed the problem, you have just renamed it: that token now has the standing privilege to read everything, and it lives in exactly the places this lesson is about.

Bad vs good secret-zero
1static token
long-lived secret shipped in env/Secret
2platform identity
K8s SA JWT / cloud IAM the workload already has
3attested exchange
manager verifies identity with the platform
4short-lived token
scoped, minutes-long, auto-renewed
The good path never ships a secret — it exchanges an identity the platform already vouches for.
Never solve secret-zero with another static secret
Wrapping a long-lived token in Vault, a Kubernetes Secret, or a baked-in env var does not solve secret-zero — it relocates it and usually widens its privilege. The only real solutions exchange a platform-native identity the workload already holds (a Kubernetes service-account JWT, an AWS instance role, a SPIFFE SVID) for a short-lived, scoped token. If your bootstrap credential is a file you copied, you still have the problem.
the leak surfaces are trivially real
# a secret in an env var is readable by anything local:
$ cat /proc/$(pgrep -f myapp)/environ | tr "\0" "\n" | grep -i token
APP_DB_PASSWORD=s3cr3t-shared-prod
# and it follows the process into crash dumps, child processes, and
# any log line that dumps the environment on error. env vars are not a vault.