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:
@@ -297,6 +297,17 @@ type Manifest struct {
|
||||
// module, in a file anybody can read, for ever.
|
||||
OwnSecrets map[string]string `json:"own-secrets,omitempty"`
|
||||
|
||||
// Keeps is where this module wants every operator-sealed secret in the mesh written — the
|
||||
// vault's field, and so far nobody else's (novox/hq ADR 0085, amended).
|
||||
//
|
||||
// A directory. The mesh writes one file into it, `export.json`: every secret a module holds for
|
||||
// itself, sealed to the operator's key, with the key's public half and the list of what is NOT
|
||||
// in it. Ciphertext to the machine that holds it and to everything on the bus it crossed —
|
||||
// only the operator, holding the private half off the mesh, can open a line of it. That is
|
||||
// what lets a vault's disk stand in for the store when the store is gone: recovery needs the
|
||||
// export and the key, and the mesh holds neither in a form it can use.
|
||||
Keeps string `json:"keeps,omitempty"`
|
||||
|
||||
// Listens is what this module accepts connections on, and from where.
|
||||
//
|
||||
// **A rule names its source** ([ADR 0007](novox/hq)). A port with no source is open to
|
||||
@@ -918,6 +929,10 @@ func ParseManifest(raw []byte) (Manifest, error) {
|
||||
"%s grants %q to its consumers and does not provide it", m.Module, to))
|
||||
}
|
||||
}
|
||||
if m.Keeps != "" && !strings.HasPrefix(m.Keeps, "/") {
|
||||
problems = append(problems, fmt.Sprintf(
|
||||
"%s keeps the operator-sealed secrets at %q, which is not an absolute path", m.Module, m.Keeps))
|
||||
}
|
||||
for to, where := range m.Receives {
|
||||
if !name.MatchString(to) {
|
||||
problems = append(problems, fmt.Sprintf("%q is not a usable name to receive", to))
|
||||
|
||||
Reference in New Issue
Block a user