Hand off the secrets vault to mesh-catalog; open issues 069 and 070
Design 24 flips to in-progress with mesh-catalog as its owner (playbook 04). Starting the build surfaced two gaps the decision did not settle: a module requiring `secret` receives exactly one value (069), and no command can accept an operator's value into a consumer↔vault pair (070). Both opened as issues rather than improvised around. Also fills fixed-by on 067 and 068, which the cycle check refused as resolved with no reference.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
layer: to-be
|
layer: to-be
|
||||||
status: designed
|
status: in-progress
|
||||||
code: []
|
code: [mesh-catalog]
|
||||||
updated: 2026-09-20
|
updated: 2026-09-20
|
||||||
decisions:
|
decisions:
|
||||||
- 02-DECISIONS/0085-a-secret-is-a-provision.md
|
- 02-DECISIONS/0085-a-secret-is-a-provision.md
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
status: resolved
|
status: resolved
|
||||||
opened: 2026-09-20
|
opened: 2026-09-20
|
||||||
located-in: []
|
located-in: []
|
||||||
fixed-by:
|
fixed-by: graduated — hq fc4ab37 (ADR 0084, to-be design 23)
|
||||||
amended-design: 03-DESIGN/01-to-be/23-choosing-a-provider.md
|
amended-design: 03-DESIGN/01-to-be/23-choosing-a-provider.md
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
status: resolved
|
status: resolved
|
||||||
opened: 2026-09-20
|
opened: 2026-09-20
|
||||||
located-in: []
|
located-in: []
|
||||||
fixed-by:
|
fixed-by: graduated — hq fc4ab37 (ADR 0085, to-be design 24)
|
||||||
amended-design: 03-DESIGN/01-to-be/24-the-secrets-vault.md
|
amended-design: 03-DESIGN/01-to-be/24-the-secrets-vault.md
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
status: open
|
||||||
|
opened: 2026-09-20
|
||||||
|
located-in: []
|
||||||
|
fixed-by:
|
||||||
|
amended-design:
|
||||||
|
---
|
||||||
|
|
||||||
|
# One `secret` provision yields one value, and a module may need several
|
||||||
|
|
||||||
|
## Symptom, as observed
|
||||||
|
|
||||||
|
[ADR 0085](../../02-DECISIONS/0085-a-secret-is-a-provision.md) makes a module's own secret a
|
||||||
|
provision: the module requires `secret` from a vault and reads the pair credential the mesh
|
||||||
|
minted for that consumer↔vault pair. A pair has **exactly one** credential — that is the property
|
||||||
|
[13](../../03-DESIGN/01-to-be/13-credentials-and-their-rotation.md) is built on, and the reason
|
||||||
|
rotation touches one holder and nothing else.
|
||||||
|
|
||||||
|
A module may only require a provision name once, so a module that requires `secret` receives
|
||||||
|
**one value**. Counted across the catalogue at the time of writing, a module's own secrets other
|
||||||
|
than its broker account number as follows:
|
||||||
|
|
||||||
|
| own secrets | modules |
|
||||||
|
|---|---|
|
||||||
|
| one | 22 |
|
||||||
|
| two | 6 (an internal token and an admin password, a user and a password for an outbound mail relay, …) |
|
||||||
|
| three or more | 4 (a source, an admin and a relay password; a root certificate, its key and that key's password; …) |
|
||||||
|
|
||||||
|
Ten modules cannot be migrated onto the vault as designed, because the design gives them one
|
||||||
|
value where they hold two or more, and nothing in the record says what they should do instead.
|
||||||
|
|
||||||
|
## Why it matters beyond this instance
|
||||||
|
|
||||||
|
- **The migration in ADR 0085 is "module by module, not a flag day"** — but for a third of the
|
||||||
|
modules with own secrets there is no target to migrate to, and the gap is silent: such a
|
||||||
|
module keeps `own-secrets` for the rest and looks migrated.
|
||||||
|
- **Two candidate answers pull in different directions and neither is recorded.** A module could
|
||||||
|
derive several keys from its one value (a key-derivation step inside the module, which puts
|
||||||
|
cryptography into every module that needs two secrets), or the mesh could let a consumer
|
||||||
|
require several *named* secrets from one vault (which is a pair with several credentials, the
|
||||||
|
thing 13 deliberately does not have, or several pairs between the same two modules, which the
|
||||||
|
identity derivation in [ADR 0049](../../02-DECISIONS/0049-a-consumers-identity-fits-the-tightest-backend.md)
|
||||||
|
cannot express).
|
||||||
|
- **A secret with structure is not one value either.** A certificate authority's root
|
||||||
|
certificate, key and key password are three things with one lifecycle; a value the controller
|
||||||
|
mints at random is none of them. The vault's third species — an operator-delivered secret — is
|
||||||
|
the nearer fit, and it has its own gap ([070](../070-an-operator-cannot-deliver-a-pair-credential/00-report.md)).
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- Is "one value per module" a rule to keep, with derivation the module's business, or does a
|
||||||
|
consumer name several secrets and the vault serve each as its own pair?
|
||||||
|
- If the latter: what is the login of the second pair between the same consumer and the same
|
||||||
|
vault, given that a login is derived from the (node, module) pair and is what the secret is
|
||||||
|
keyed on?
|
||||||
|
- Which modules genuinely need several independent secrets, and which hold two names for one
|
||||||
|
thing (an admin password and a token that is only ever set from it)?
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
status: open
|
||||||
|
opened: 2026-09-20
|
||||||
|
located-in: [mesh-controller]
|
||||||
|
fixed-by:
|
||||||
|
amended-design:
|
||||||
|
---
|
||||||
|
|
||||||
|
# An operator cannot deliver a pair credential, so the vault's third species has no entry
|
||||||
|
|
||||||
|
## Symptom, as observed
|
||||||
|
|
||||||
|
[ADR 0085](../../02-DECISIONS/0085-a-secret-is-a-provision.md) names three species of secret and
|
||||||
|
gives the vault two: a module's own secret, which the mesh mints, and an **operator-delivered**
|
||||||
|
secret — a credential for something outside the mesh, which only a person can supply. The design
|
||||||
|
([24](../../03-DESIGN/01-to-be/24-the-secrets-vault.md)) says the vault *"takes custody of one an
|
||||||
|
operator delivered"*.
|
||||||
|
|
||||||
|
Under 0085 a secret from the vault is a pair credential between the consumer and the vault. The
|
||||||
|
controller has one command that takes a value from a person — `secret accept` — and it writes
|
||||||
|
**only a module's own secret**: one node, one module, one name, sealed to that node's key alone.
|
||||||
|
There is no command that accepts a value *into a pair*: sealed to the consumer's node **and** to
|
||||||
|
the vault's node, recorded as `accepted` so a later push does not replace it with a minted one.
|
||||||
|
|
||||||
|
The primitive exists. The sealing package's `Accept` takes a value and two keys, and the licence
|
||||||
|
adapters already use it to carry an operator's token to both ends of a licence. Nothing exposes it
|
||||||
|
for an ordinary provision.
|
||||||
|
|
||||||
|
So today an operator-delivered secret can be held in only one of two wrong ways: as an own secret
|
||||||
|
(un-audited, un-rotatable — the gap 0085 opened to close), or not at all.
|
||||||
|
|
||||||
|
## Why it matters beyond this instance
|
||||||
|
|
||||||
|
- **The vault is one third short of its decision** until this exists, and the third that is
|
||||||
|
missing is the one with a real leak history — external keys are the secrets that end up in
|
||||||
|
transcripts and env files.
|
||||||
|
- **The `made`/`accepted` distinction is only recorded for own secrets.** A pair credential has no
|
||||||
|
origin column, so even once a value can be accepted into a pair, `rotate` would mint over it —
|
||||||
|
generating "32 random bytes where a working credential was", the exact fault `secret accept`
|
||||||
|
was written to prevent for own secrets. Rotating an accepted pair credential must refuse, or
|
||||||
|
must ask for the replacement value, and neither is designed.
|
||||||
|
- **The consumer's login is derived, and an external service did not derive it.** An accepted
|
||||||
|
external key has no `as` the far side knows; a pair credential assumes both ends agree on one.
|
||||||
|
For the vault this is harmless (the vault creates nothing under that login), but the model
|
||||||
|
leaks through in what the consumer is told.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
- Is this `secret accept <consumer-node> <module> secret --from …` growing a provider end, or a
|
||||||
|
new verb on the pair?
|
||||||
|
- Does an accepted pair credential refuse `rotate`, or does `rotate` become "accept a new value
|
||||||
|
and deliver it" for that pair?
|
||||||
|
- Should the origin (`made` / `accepted`) become a fact of every pair credential, so the vault's
|
||||||
|
ledger can show which of its secrets a person supplied?
|
||||||
Reference in New Issue
Block a user