Apply review: two credentials, staged admin rotation, a ninth provider
The fact-check found mailu, whose user is its mailbox, so 0114 rotates over two credentials rather than two logins, the adapter choosing what a credential is. Also: minio keeps non-empty buckets; five backends take their admin credential only at first init, so single-party rotation is staged; postgres ownership moves to a non-login role; the harness keys by consumer; rotation state lives with the vault. Consistency fixes across 0110-0113, 26 and 27; issue 103 resolved by mesh-host PR #22.
This commit is contained in:
@@ -15,7 +15,7 @@ controller on 2026-09-25:
|
||||
|
||||
| kind | made by | used by |
|
||||
|---|---|---|
|
||||
| a credential between a consumer and a provider | the controller | 19 modules |
|
||||
| a credential between a consumer and a provider | the controller | 16 modules, and 3 more for model access, counted below |
|
||||
| a module's own secret (`own-secrets`) | the controller, as a random value nothing owns | 54 modules |
|
||||
| a module's broker account | the controller, but only when a person runs a separate command; otherwise the random value above, which cannot work ([issue 095](../04-ISSUES/095-a-module-assigned-after-genesis-has-no-broker-account/00-report.md)) | 49 modules |
|
||||
| a node's and the builder's broker accounts | the controller, each in its own code path | every node, the builder |
|
||||
@@ -78,7 +78,7 @@ it first means reordering the whole installation and giving the vault a second w
|
||||
requiring a database makes the database's provider require a secret for gitea, and the vault
|
||||
answers it. The provider's own code does not change: it is handed a login and a password, as today;
|
||||
- a module's **own secret**. `own-secrets` is retired;
|
||||
- every **broker account** on the mesh's bus: a module's, a node agent's, the builder's, the
|
||||
- every **broker account** on the mesh's bus: a module's, a node's host's, the builder's, the
|
||||
controller's. The broker holding `mesh-broker` carries the mesh's bus
|
||||
([ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md)), and its own provisioner creates
|
||||
each account from the vault's secret, like any provider. The controller no longer creates accounts,
|
||||
@@ -122,9 +122,11 @@ generated by genesis:
|
||||
token.
|
||||
|
||||
Until the broker's provisioner runs, genesis creates the bus accounts it generated, with the broker's
|
||||
admin, as the controller does today. Genesis seals all of it to the control-node's key, and when the vault
|
||||
is installed the controller **delivers the values to the vault, recorded as the mesh's own**, not as an
|
||||
operator's. Nobody has to be present for it.
|
||||
admin, as the controller does today. Genesis seals each value twice: to the control-node's key, so that when the
|
||||
vault is installed the controller **delivers the values to the vault, recorded as the mesh's own**, not
|
||||
as an operator's, with nobody present; and to the operator key, as the break-glass copy
|
||||
[ADR 0085](0085-a-secret-is-a-provision.md) keeps of every root secret. The first enrolment token reaches
|
||||
the operator the same way.
|
||||
That distinction matters: an operator's value is never replaced ([ADR 0092](0092-an-operator-delivers-a-pair-credential.md)),
|
||||
and these are, because the vault can make their replacements. The broker's provisioner then adopts the
|
||||
accounts genesis created. From then on the vault makes every shared secret, and genesis has made its
|
||||
@@ -132,7 +134,9 @@ last one.
|
||||
|
||||
**Raising the vault or the broker again is a genesis act.** Moving the `mesh-vault` or `mesh-broker`
|
||||
seat to a new assignment, or recovering either after it is lost, is done the way genesis did it: the
|
||||
values it needs are delivered, not made by a vault that is not there. That is a break-glass procedure,
|
||||
values it needs are delivered, not made by a vault that is not there. They come from the operator-sealed
|
||||
copies, which the operator opens. The vault keeps a copy of every secret sealed to the operator key
|
||||
(0085), so nothing the mesh relies on exists only inside the vault. That is a break-glass procedure,
|
||||
stated and checked, never an ordinary assignment.
|
||||
|
||||
**A provider makes resources and data, and the mesh carries data back.** A provider's adapter may
|
||||
@@ -149,14 +153,17 @@ not rotated by the vault: rotating it means an operator delivering a new one. A
|
||||
issued is rotated by the module that holds the backend asking it again and delivering the new value to
|
||||
the vault.
|
||||
|
||||
**Each recipient takes a new value one of two ways, marked on its requirement:**
|
||||
**Each recipient takes a new value one of two ways, marked per recipient:**
|
||||
|
||||
| recipient takes it by | example | what happens on rotation |
|
||||
|---|---|---|
|
||||
| **applying** it | a provider setting a login's password; the broker's provisioner updating an account; a store's provisioner changing its own superuser | its provisioner applies the new value; it is never restarted for it |
|
||||
| **reading it at start** | a consumer reading its password when it starts | the host recreates it, because a file it read at creation changed |
|
||||
|
||||
The marking is on each requirement, not on the secret, because one secret has recipients of both kinds.
|
||||
The marking is per recipient, not per secret, because one secret has recipients of both kinds. A
|
||||
provision's contract marks its provider's side, which applies. A consumer's side is read at start
|
||||
unless its requirement says otherwise. The broker's contract marks the host's bus account the same
|
||||
way: the broker's provisioner applies it, and the host reads it.
|
||||
Every module in the catalogue reads its secrets at start, and none watches them
|
||||
([research 016](../01-RESEARCH/016-how-a-credential-can-be-rotated/02-the-readers.md)). A secret a
|
||||
backend takes only when it first initialises is marked applied, and its provider's provisioner makes
|
||||
@@ -165,7 +172,7 @@ rotatable by the mesh**, and a rotation request is refused, saying why, rather t
|
||||
that would carry on with the old value.
|
||||
|
||||
**How old and new change over is decided in [ADR
|
||||
0114](0114-a-shared-credential-rotates-over-two-logins.md).** Three mechanisms were measured against
|
||||
0114](0114-a-shared-credential-rotates-over-two-credentials.md).** Three mechanisms were measured against
|
||||
every provider's code in [research
|
||||
016](../01-RESEARCH/016-how-a-credential-can-be-rotated/00-overview.md): in place, as the controller's
|
||||
`rotate` does today; two secrets on one login; and two logins over one resource. Its findings bound the
|
||||
@@ -173,15 +180,15 @@ choice:
|
||||
|
||||
- every credential provider already re-applies a password in place, so today's rotation works, with a
|
||||
window in which a consumer cannot authenticate;
|
||||
- seven of eight name the consumer's resource after its login, and five destroy the resource when they
|
||||
remove the login. **No mechanism may retire a login through today's remove**, because in those five
|
||||
it deletes the consumer's data;
|
||||
- only one backend holds two passwords on one login;
|
||||
- every backend can give two logins the same rights over one resource, once the adapter separates the
|
||||
resource from the login.
|
||||
- eight of nine name the consumer's resource after its login, and five destroy the consumer's data when
|
||||
they remove the login. **No mechanism may retire a login through today's remove**, because in those
|
||||
five it deletes the consumer's data;
|
||||
- one backend holds two passwords on one login, and two more hold several tokens;
|
||||
- every provider can hold two credentials over one resource, eight as two logins and one as two tokens,
|
||||
once the adapter separates the resource from the credential.
|
||||
|
||||
On those facts, 0114 rotates a credential two parties hold over two logins, rotates one a single
|
||||
party holds in place, and separates retiring a login from removing a consumer.
|
||||
On those facts, 0114 rotates a credential two parties hold over two credentials, rotates one a single
|
||||
party holds in place, staged, and separates retiring a credential from removing a consumer.
|
||||
|
||||
## What this changes in earlier records
|
||||
|
||||
@@ -192,7 +199,9 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
credential and seals nothing stands.
|
||||
- [ADR 0085](0085-a-secret-is-a-provision.md) is amended: the vault makes every shared secret, own
|
||||
secrets are retired, and its rejection of vault-only minting is answered by genesis delivering the
|
||||
first secrets. "The vault stores no plaintext, ever" stands.
|
||||
first secrets. Genesis seals its values to the control-node's key as well as to the operator key, so
|
||||
the controller can deliver them unattended. "The vault stores no plaintext, ever" and the
|
||||
operator-sealed break-glass copies stand.
|
||||
- [ADR 0092](0092-an-operator-delivers-a-pair-credential.md) is amended: an operator delivers a secret
|
||||
to the vault. Genesis's values reach the vault by delivery too, but are recorded as the mesh's own,
|
||||
so 0092's rule that an operator's value is never replaced does not apply to them.
|
||||
@@ -201,9 +210,14 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
- [To-be 13](../03-DESIGN/01-to-be/13-credentials-and-their-rotation.md),
|
||||
[to-be 21](../03-DESIGN/01-to-be/21-the-installation-in-full.md) and
|
||||
[to-be 24](../03-DESIGN/01-to-be/24-the-secrets-vault.md) are amended: the vault makes a rotated value and each
|
||||
requirement says whether its recipient applies it or reads it at start, while the changeover
|
||||
mechanism stays as to-be 13 describes until its own record; the vault is installed as soon as the
|
||||
requirement says whether its recipient applies it or reads it at start, and the changeover is
|
||||
[ADR 0114](0114-a-shared-credential-rotates-over-two-credentials.md)'s; the vault is installed as soon as the
|
||||
shared runtime base exists, and genesis delivers its secrets to it; the vault is the only maker.
|
||||
- [To-be 07](../03-DESIGN/01-to-be/07-the-foundation.md) is amended: genesis seals its values to
|
||||
the control-node's key as well as the operator key.
|
||||
- [To-be 12](../03-DESIGN/01-to-be/12-a-module-repository.md), [to-be 16](../03-DESIGN/01-to-be/16-module-coverage.md)
|
||||
and [to-be 18](../03-DESIGN/01-to-be/18-building-a-module.md) are amended: `own-secrets` is retired from the
|
||||
manifest they describe.
|
||||
- The [glossary](../00-META/glossary.md) gains *shared secret*, *recipient*, *applies* and *reads at
|
||||
start*, and *reserved provision*, once this record is accepted.
|
||||
- [Issue 103](../04-ISSUES/103-a-container-is-not-recreated-when-a-file-it-reads-changes/00-report.md)
|
||||
@@ -217,7 +231,7 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
- Resolution expands per-consumer requirements from a provision's contract. The contract declares
|
||||
them, never the provider's code, so what a provider requires stays predictable from the catalogue.
|
||||
- A data provider's adapter gains a return value. What a credential provider's adapter must change for
|
||||
rotation is [ADR 0114](0114-a-shared-credential-rotates-over-two-logins.md)'s.
|
||||
rotation is [ADR 0114](0114-a-shared-credential-rotates-over-two-credentials.md)'s.
|
||||
- The broker's provisioner gains every bus account, and the controller loses five separate places it
|
||||
generates a secret today.
|
||||
- 54 modules move from own secrets to vault requirements. Six provider clients export a password
|
||||
@@ -236,7 +250,7 @@ On acceptance, each of these is superseded or amended by this record, not edited
|
||||
| A private key is made where it is used | A test per key: a node's sealing key never leaves the node, the operator's private key never enters the mesh, and the certificate authority's private key never leaves the controller's identity store. |
|
||||
| Only the vault provides `secret` | The parser refuses a definition providing `secret` that cannot hold `mesh-vault`, and resolution refuses a pin on a `secret` requirement. |
|
||||
| The controller and each node's host take the same path | A catalogue test: the controller's definition declares no own secret, only requirements. A controller test: a node's bus account is made by the vault and delivered sealed to that node; an enrolment token reaches the controller only as what verifies it. |
|
||||
| Genesis's values reach the vault unattended | An installer test: genesis's values are sealed to the control-node's key and delivered by the controller when the vault is installed, with no operator step. |
|
||||
| Genesis's values reach the vault unattended, and the operator keeps a copy | An installer test: each of genesis's values is sealed to the control-node's key and to the operator key; the controller delivers the first to the vault when it is installed, with no operator step; the operator's copy opens only with the operator key. |
|
||||
| Moving the vault or broker is a procedure | A resolution test: an ordinary assignment moving `mesh-vault` or `mesh-broker` is refused, naming the procedure. |
|
||||
| A backend-issued secret enters through the vault | A vault test: a value delivered as issued is provided like any other, and rotating it is refused as the vault's act. |
|
||||
| A secret with no provisioner to apply it is not rotated by restart | A vault test: rotating a secret whose requirement is marked not rotatable by the mesh is refused, naming why. |
|
||||
|
||||
Reference in New Issue
Block a user