Overlap as drafted in 0113 would have deleted consumer data: seven of eight providers name the resource after the login and five drop it on remove. Rotation is now undecided in 0113 and to-be 27, pending the survey. Also: a requirement naming a seat resolves to its holder, a person chooses among remaining candidates at assignment, the controller's secrets are requirements of its definition, genesis seals to the control-node key, and moving the vault or broker is break-glass.
76 lines
4.4 KiB
Markdown
76 lines
4.4 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 eight
|
|
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 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 logins per consumer, over one resource
|
|
|
|
The consumer has two logins derived by the mesh, and uses one at a time. The applier creates the other
|
|
with the new value and grants it the same rights over the consumer's resource. Readers move to it,
|
|
and then the old login is retired, which removes the login only, never the resource.
|
|
|
|
- **Works with:** every backend (finding 5), **after** each adapter changes:
|
|
- the resource is named after the consumer, not the login. Today the two are the same string (finding
|
|
7), so existing resources keep their names, the current login stays one of the two, and only the
|
|
second is new;
|
|
- both logins get the same rights, through a group role or its equivalent;
|
|
- *retire a login* and *remove the consumer* become two operations. Today they are one call, and
|
|
in five providers that call destroys data (finding 3). This is the whole of the danger, and it has
|
|
to be split, whatever else is chosen.
|
|
- **Costs:**
|
|
- seven adapters change;
|
|
- the harness learns the alternation and a confirmation per step;
|
|
- 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;
|
|
- an MQTT client identifier stays unique per connection, so mosquitto needs the client id kept apart
|
|
from the login.
|
|
- **Gains:** no window. A reader that cannot be reached keeps a working login 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.** Retiring a credential must never be able to destroy a consumer's data. That holds
|
|
under A too, because A's remove is the same call. A remove that drops a database should be a
|
|
separate, explicit operation, which [ADR 0030](../../02-DECISIONS/0030-data-outlives-the-mesh-that-declared-it.md)
|
|
already implies: data outlives the declaration.
|
|
- **Admin credentials are applied by their own provider**, using the old value. That happens in place
|
|
whichever mechanism consumers get. Where a backend takes the value only at first initialisation, the
|
|
file alone changes nothing, and rotation needs the provider's provisioner to run the change.
|
|
- **Classify the 22 readers** ([02](02-the-readers.md)) before relying on derived restarts.
|
|
|
|
## Recommendation
|
|
|
|
- **Consumer credentials: C**, because it is the only mechanism every backend 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.** In place, applied by the provider
|
|
that holds them.
|
|
- **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.
|