Files
hq/01-RESEARCH/016-how-a-credential-can-be-rotated/03-the-options.md
jochen e387c4bd0e 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.
2026-09-26 00:38:06 +02:00

4.8 KiB

03 — The options

Three mechanisms, weighed against 01 and 02.

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), 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), 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.