ADR 0113 and to-be 27: rotation overlaps old and new credentials
Decided with the author. A credential is never changed in place: each consumer has two logins, both derived by the mesh, and uses one at a time. An applier adds the new login beside the old through the adapter's existing create, and confirms both work; only then are readers released to the new one and restarted by derivation; only when every reader has confirmed is the old login retired through the existing remove. It closes the three cases review found in applier-first rotation: an offline reader keeps working on the old login until it returns; a bus account's owner keeps its bus until it has moved; a provisioner restarted mid-rotation is still delivered both values. Nobody is ever without a credential that works, which replaces to-be 13's all-or-nothing rule with a stronger one. No consumer module changes. The alternation is the provider loop's. A provider's adapter gains one duty, giving both logins the same rights over the consumer's data — in postgres, membership of one role that owns it. The mesh derives two logins per consumer, both within ADR 0049's limit, which 0113 now names among what it amends. Every rule has a check: overlap, offline reader, bus account, restarted provisioner, equal rights, login length, and confirmation only once the old login is gone.
This commit is contained in:
@@ -233,26 +233,32 @@ through a provisioner (a provider creating the login, the broker's provisioner u
|
||||
the store's own provisioner changing its superuser), or *reads it at start*. A secret a service reads
|
||||
only when it first initialises is marked applied, because a restart would change nothing.
|
||||
|
||||
1. **The vault makes the new value.**
|
||||
2. **It goes first to the recipients that apply it.** Each applies it, verifies that the new value
|
||||
authenticates and the old one no longer does, and confirms. It repeats that confirmation on every
|
||||
reconcile pass until the vault acknowledges it, so a lost message costs one pass.
|
||||
3. **Only then is it released to the recipients that read it at start**, such as gitea.
|
||||
4. **The host restarts every such recipient**, and recreates a container whose env-file carries the
|
||||
secret. It knows which, because a definition reads a secret only through its requirement, so no
|
||||
definition declares a restart for a secret. An applying recipient is never restarted for it.
|
||||
This needs [issue 103](../../04-ISSUES/103-a-container-is-not-recreated-when-a-file-it-reads-changes/00-report.md)
|
||||
fixed, or a container fed by an env-file keeps the old value.
|
||||
5. **It is confirmed.** The rotation shows as unconfirmed until every applier has confirmed, and every
|
||||
recipient that reads at start has restarted and passed its health check, where its definition
|
||||
declares one. Delivered and working are shown as different things.
|
||||
**Old and new overlap, so nobody is ever without a credential that works.** A credential is never
|
||||
changed in place. Each consumer has two logins, both derived by the mesh, and uses one at a time:
|
||||
|
||||
**Open: keeping readers from being locked out.** Steps 2 and 3 leave a reader locked out when its
|
||||
machine is offline after an applier applied, when the secret is a bus account whose owner loses the bus
|
||||
it would hear the new value on, or when a restarted provisioner can no longer check the old value.
|
||||
[ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md) records the two answers, overlapping
|
||||
old and new credentials or re-confirming with safeguards, and one is chosen before it is accepted.
|
||||
Neither changes a consumer module.
|
||||
1. **The vault makes the new value.**
|
||||
2. **Each applier adds it beside the old**, as the consumer's other login, through the adapter's
|
||||
existing create. It verifies that the new login works and the old one still does, and confirms,
|
||||
repeating that confirmation on every reconcile pass until the vault acknowledges it.
|
||||
3. **Only then is the new login released to the readers**, such as gitea, login and value together.
|
||||
4. **The host restarts every such reader**, and recreates a container whose env-file carries the
|
||||
secret. It knows which, because a definition reads a secret only through its requirement, so no
|
||||
definition declares a restart for a secret. An applier is never restarted for it. This needs
|
||||
[issue 103](../../04-ISSUES/103-a-container-is-not-recreated-when-a-file-it-reads-changes/00-report.md)
|
||||
fixed, or a container fed by an env-file keeps the old value.
|
||||
5. **Each reader confirms** by passing its health check with the new login, where its definition
|
||||
declares one.
|
||||
6. **Only when every reader has confirmed is the old login retired**, through the adapter's existing
|
||||
remove, and verified to no longer authenticate.
|
||||
|
||||
So a reader whose machine is offline keeps working on the old login until it returns, a bus account's
|
||||
owner keeps its bus until it has moved, and a provisioner restarted mid-rotation is still delivered
|
||||
both values. The rotation shows as waiting on whichever applier or reader has not moved, and is done
|
||||
only when the old login is gone.
|
||||
|
||||
**No consumer module changes.** A provider's adapter gains one duty: both of a consumer's logins get the
|
||||
same rights over its data, which in postgres means both belong to one role that owns it. The
|
||||
alternation itself is the provider loop's.
|
||||
|
||||
A secret some service reads only when it first initialises cannot be rotated by restarting it. It is
|
||||
applied by a provisioner, or, where none exists, marked not rotatable by the mesh, and a rotation is
|
||||
@@ -304,8 +310,8 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
mesh carries providers' data back.
|
||||
[Issue 103](../../04-ISSUES/103-a-container-is-not-recreated-when-a-file-it-reads-changes/00-report.md)
|
||||
is fixed first. *Ends when* nothing outside the vault generates a shared secret after genesis, a lab
|
||||
consumer of analytics receives its site id, and a database credential rotates applier-first, with
|
||||
the consumer restarted by derivation and the rotation confirmed.
|
||||
consumer of analytics receives its site id, and a database credential rotates with old and new
|
||||
overlapping, the consumer restarted by derivation and the rotation confirmed.
|
||||
3. **Definitions move, and seats move to assignments.** Every catalogue definition is rewritten, adopted
|
||||
and running assignments placed where their data already is, and each claim becomes a seat the
|
||||
module can hold, held by the assignment that holds it today. *Ends when* the list of definitions
|
||||
@@ -331,7 +337,7 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
| Only the vault generates a shared secret after genesis | A controller test: no code path generates one. An installer test: genesis generates exactly the foundation's first secrets and delivers them to the vault. |
|
||||
| Only the vault provides `secret` | The parser refuses another provider of it, and resolution refuses a pin on a `secret` requirement. |
|
||||
| A provider's per-consumer secret comes from the vault | A resolution test: requiring a database expands to a secret requirement named for the consumer, answered by the vault and delivered to both recipients. |
|
||||
| Rotation is applier-first, derived and confirmed | The rotation tests of [ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md): readers wait for every applier's repeated confirmation; an applied secret restarts nothing, and one read at start restarts its reader without a declared restart; the rotation shows unconfirmed until the new value authenticates, the old does not, and readers are healthy. |
|
||||
| Rotation overlaps old and new | The rotation tests of [ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md): both logins authenticate while readers move; an offline reader keeps working on the old login; the old login is retired only after every reader confirms; an applied secret restarts nothing, and one read at start restarts its reader without a declared restart. |
|
||||
| Refusal names everything at once | A resolution test with three unresolved requirements of different kinds: one refusal naming all three. |
|
||||
| The old forms retire | The catalogue test listing definitions still using one. It must be empty before a form is removed. |
|
||||
|
||||
@@ -341,5 +347,3 @@ Each phase ends at a check that holds, so none of them leaves a mechanism half-r
|
||||
- The layout a node's default root uses beneath it, beyond one directory per assignment.
|
||||
- Whether a module provider's answer can change without the provider being asked, for example a
|
||||
provider moving. The rule so far is that it cannot, and moving is re-resolving.
|
||||
- **How rotation keeps a recipient from being locked out.** Under review: see
|
||||
[ADR 0113](../../02-DECISIONS/0113-the-vault-makes-every-secret.md), rotation.
|
||||
|
||||
Reference in New Issue
Block a user