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.
80 lines
4.8 KiB
Markdown
80 lines
4.8 KiB
Markdown
# 03 — The options
|
|
|
|
Three mechanisms, weighed against [01](01-the-providers.md) and [02](02-the-readers.md).
|
|
|
|
## A. In place, as today
|
|
|
|
The vault makes a new value. Every applier re-applies it on the same login, which all nine
|
|
providers already do. Every reader is recreated by the host.
|
|
|
|
- **Works with:** every provider, unchanged. It is what `rotate` does now.
|
|
- **Costs:** a window per consumer, from the provider applying to the consumer being recreated. They
|
|
are on different machines, and nothing orders them. A reader whose machine is unreachable from the
|
|
mesh but still reaches its provider stays locked out until the mesh reaches it again.
|
|
- **Admin credentials:** the natural form. The provider module is the only party, and it has to
|
|
apply the new value with the old one anyway (finding 6).
|
|
|
|
## B. Two secrets on one login
|
|
|
|
The applier adds the new password beside the old one, readers move, and the old one is removed.
|
|
|
|
- **Works with:** redis natively, and gitea and mailu through tokens. **Not** with the other six, whose
|
|
backends hold one password per login (finding 4).
|
|
- **Verdict:** not a mechanism, a special case. Using it where it exists and something else
|
|
elsewhere is the "this way or that way" the design is trying to remove.
|
|
|
|
## C. Two credentials per consumer, over one resource
|
|
|
|
The consumer has two credentials and uses one at a time. The applier ensures the other with the new
|
|
value and gives it the same rights over the consumer's resource. Readers move to it, and then the old
|
|
credential is retired, which removes the credential only, never the resource. **What a credential is,
|
|
is the adapter's**: a second login for eight providers (finding 5), a second token on the same login
|
|
for mailu. The mesh sees one mechanism.
|
|
|
|
- **Works with:** every provider, **after** each adapter changes:
|
|
- the resource is named after the consumer, not the login. Today the two are the same string (finding
|
|
8), so existing resources keep their names, and the current login stays one of the two;
|
|
- the resource is owned by the resource, not by a login. In postgres that is a role no one logs in
|
|
as, which each login works as, and ownership of an existing database moves to it once (finding 6);
|
|
- both credentials get the same rights, over data and structure;
|
|
- *retire a credential* and *remove the consumer* become two operations. Today they are one call, and
|
|
in five providers that call destroys data (finding 3). The harness must key by consumer, so that a
|
|
changed login is not a removal. This is the whole of the danger, and it has to be split, whatever
|
|
else is chosen.
|
|
- **Costs:**
|
|
- every credential adapter changes;
|
|
- the harness learns the alternation and a confirmation per step, and rotation state has to live
|
|
somewhere that survives a restart, which the harness's memory does not;
|
|
- the second login's name must fit the tightest backend. That is 20 characters for a minio access
|
|
key ([ADR 0049](../../02-DECISIONS/0049-a-consumers-identity-fits-the-tightest-backend.md)), and
|
|
a suffix spends part of it;
|
|
- retiring an mssql login has to end its sessions first.
|
|
- **Gains:** no window. A reader that cannot be reached keeps a working credential until it can.
|
|
- **Does not apply to** single-party secrets: admin credentials and a module's own secrets. There is
|
|
no second party to overlap with.
|
|
|
|
## Independent of the choice
|
|
|
|
- **Split remove, and key the harness by consumer.** Retiring a credential, or a login changing, must
|
|
never be able to destroy a consumer's data. That holds under A too, because A's remove is the same
|
|
call.
|
|
- **Admin credentials are applied by their own provider**, using the old value, with the new one staged
|
|
beside it. Five backends take the value only at first initialisation. Replacing the file first locks
|
|
the provisioner out (finding 7).
|
|
- **Classify the readers** ([02](02-the-readers.md)), bus-account readers included, before relying on
|
|
derived restarts.
|
|
|
|
## Recommendation
|
|
|
|
- **Two-party credentials, consumer credentials and bus accounts: C**, because it is the only
|
|
mechanism every provider supports, and it closes the window instead of shortening it. Its prerequisite, separating the resource from the login and
|
|
retiring a login from removing a consumer, is worth doing on its own, because it removes a
|
|
data-loss path that exists today.
|
|
- **Single-party secrets (admin credentials, a module's own): A, staged.** In place, applied by the
|
|
provider that holds them, with the new value beside the old until it has taken.
|
|
- **Until the adapters are changed, A stays** as `rotate` implements it, with its window stated. It is
|
|
not replaced by a mechanism the providers cannot yet carry.
|
|
|
|
This is two mechanisms, split by a property of the secret rather than by provider: whether it has one
|
|
party or two. Every provider is treated the same way for the same kind of secret.
|