3.2 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| the tiers | accepted | 2026-09-21 | jochen | false | 02-DECISIONS/0085-a-secret-is-a-provision.md |
94. A module may hold several secrets from one provider, each a pair of its own
Context
ADR 0085 makes a module's own secret a provision: the module
requires secret from the vault and reads the pair credential minted for that consumer↔vault
pair. A pair has one credential, a module requires a provision once, and so a module received
one value. Read against the catalogue, nine modules hold two or more secrets besides their
broker account; seven of them hold genuinely independent values with independent lifetimes — a
root certificate, its key and that key's password; an admin password beside an API token. None
derives from another, so "one value, derivation the module's business" answers nothing
(issue 069).
Considered Options
- One value per module; the module derives the rest. Rejected: the values are independent.
- Require the provision several times. Rejected:
requiresis a list of names, and a requirement is matched by name everywhere. - The
secretsmap names several files under local names, and each local name is a pair credential of its own. Adopted.
Decision
A module's secrets entry for a requirement may be a path, as before, or an object of local
names to paths. Each local name is its own pair credential, keyed on it beside the provision,
the consumer node, the consumer module and the provider; its own file on the consumer, referred
to as ${secret:<local name>}; its own holder at the provider, named the consumer's identity
with the local name after it; and rotated apart from the others. A local name may not be one of
the module's own secrets or something it requires, so what a placeholder means is never
ambiguous. The plain shape is unchanged, and every credential that exists is the one it was.
The holder's suffix is not a login any backend checks — a secret is not a login — so the identity limit that binds a database role or an access key does not apply to it.
Consequences
The ten modules that could not move onto the vault can. What got harder: rotate secret for a
consumer rotates every local name it holds from that provider; rotating one of several is a
finer command than the mesh has, and waits for a case that needs it.
How it is checked
Manifest tests read both shapes, write them back, and refuse a colliding or unusable local name. A resolver test asserts two local names are two needs, two files with two credentials, and two holders at the provider. An inventory test asserts two local names are two rows, that rotating one leaves the other, and that the provider is told both. The vault bed installs a consumer that keeps two secrets and asserts two values delivered, two holders in the vault's ledger, and both rotated by one command.