← All decisions jacob@stephens.page
Decision Record

Runtime-injected secrets over plaintext config, with the store matched to the team

ADR 0018 · Accepted ยท in production on two fleets · ~1264 words

Context

A credential's default resting place is a plaintext file: a .env next to the app, a token in a config, a connection string in a shell script. Every copy leaks - through disk images, backups, a stray cat, a repo that was supposed to stay private. And the file is half the problem: a secret sitting in a process's config for its lifetime is readable by anything that can read that process's directory, used or not.

I operate two production fleets. One is team-operated: a small business's platform where several people and an autonomous coding agent need credentials, people join and leave, and a revoked key has to actually die. The other is solo-operated: my own server fleet, one operator, no seat budget, recovery that works offline with no vendor in the loop. One secret-management answer does not fit both - but one invariant does.

Decision

Secrets are injected into the process environment at runtime from an encrypted store, never read from plaintext at rest - and the store is chosen per operational context. The consumer contract is environment variables; no consumer knows which backend produced them.

Consequences

When I'd revisit

The selection criterion is the team, so the trigger is the team changing. A second regular operator on the solo fleet - or an agent whose secret access needs per-read audit - tips it to a broker, and the secret-env seam makes that a wrapper swap, not a migration. If the team fleet had to shed its SaaS dependencies, SOPS plus disciplined key custody is the fallback, at the cost of the audit log. A middle step short of either is hardware- or KMS-backed custody for the age key, closing the readable-by-the-shell gap without adopting a broker.


Seventh-boundary appendix

Attached to every ADR in the AI-toolchain series. It asks who is affected upstream and downstream of the automation, not only how it behaves.

One of a set of architecture decision records. Source markdown lives in the infrastructure-patterns repo, which is the canonical copy.