An operator key, a second seal on every own secret, and the vault keeps the export

novox/hq ADR 0085, amended: the mesh's root secrets — the store's superuser,
the broker's administrator, every secret a module holds for itself — were
sealed to a node key and nothing else, so a lost node took them with it.
Now the mesh records an operator's public sealing key and seals every own
secret to it as well, minted or accepted. The private half is written once
by `operator key new` to a file the operator keeps off the mesh; the mesh
holds one more blob per secret that it cannot open.

`secret recover` opens a secret with that key, to a 0600 file, from the
store or from an export; `secret export` writes every operator-sealed copy
as ciphertext. A module that `keeps` (the vault) is handed that export as a
declared file on its own disk, so recovery survives the store.

Secrets made before the key exists have no operator copy and are said so —
the plaintext was discarded — until each is issued again.
This commit is contained in:
2026-09-20 23:56:49 +02:00
parent 1c2e94e1a0
commit e140ed5d0b
13 changed files with 906 additions and 20 deletions
@@ -0,0 +1,22 @@
-- The operator's sealing key, and a second seal on every secret a module holds for itself.
--
-- Every secret here is sealed to the node that will use it and to nothing else, so a node whose key
-- is gone takes its secrets with it -- and the mesh's own root secrets, the store's superuser and
-- the broker's administrator among them, are exactly such secrets. novox/hq ADR 0085 (amended)
-- gives them a second holder: a person, with a key whose private half never enters the mesh. What
-- the mesh keeps is one more blob it cannot open.
-- At most one operator key at a time. A row rather than a setting, because it is a fact about the
-- mesh with consequences (what can be recovered), not somebody's preference about a module.
create table operator_key (
public text not null primary key,
made_at timestamptz not null default now()
);
alter table module_secret
-- The same value, sealed to the operator key -- null for a secret minted before there was
-- one, which cannot be sealed after the fact: the plaintext was discarded. Such a secret is
-- recoverable only once it is issued again.
add column operator_sealed text,
-- Which operator key, so a replaced key can be told what it can no longer open.
add column operator_key text;