64 lines
3.2 KiB
Markdown
64 lines
3.2 KiB
Markdown
---
|
|
topic: the tiers
|
|
status: accepted
|
|
date: 2026-09-21
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 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](0085-a-secret-is-a-provision.md) 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](../04-ISSUES/069-one-secret-provision-yields-one-value/00-report.md)).
|
|
|
|
## Considered Options
|
|
|
|
1. **One value per module; the module derives the rest.** Rejected: the values are independent.
|
|
2. **Require the provision several times.** Rejected: `requires` is a list of names, and a
|
|
requirement is matched by name everywhere.
|
|
3. **The `secrets` map 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.
|
|
|
|
## References
|
|
|
|
- [issue 069](../04-ISSUES/069-one-secret-provision-yields-one-value/00-report.md)
|
|
- [ADR 0085](0085-a-secret-is-a-provision.md), [ADR 0049](0049-a-consumers-identity-fits-the-tightest-backend.md)
|
|
- [`03-DESIGN/01-to-be/24-the-secrets-vault.md`](../03-DESIGN/01-to-be/24-the-secrets-vault.md)
|