package main import ( "context" "fmt" "github.com/novox/mesh-controller/internal/catalogue" "github.com/novox/mesh-controller/internal/inventory" ) // A covered account is handed to the vault when it is minted (novox/hq ADR 0374, issue 787). // // **Covered** are the bus accounts `module issue` mints for a core module (catalogue.CoreCredentialModules) or for a // module marked moved; no other account is. Until the vault makes bus accounts (ADR 0113 clause 6, issue 774) the // controller mints such an account and writes its hash to the bus's user list, as before, and then hands the whole // value at once to the vault's `accept` with origin `issued`: sealed here to the key the vault made for that call, so // the vault alone opens it (ADR 0349 clause 8). The vault keeps it as the module's own secret on that machine and // raises `secret-changed`; a re-issue is the same hand with a new value, which replaces the old in place. An account // not covered is minted and kept as it was and handed to nobody. // vaultAskerForIssue is the vault as `module issue` asks it. A test replaces it. var vaultAskerForIssue = func(ctx context.Context) vaultAsker { return theVault(ctx) } // accountIsCovered says whether the bus accounts minted for m are the vault's to hold (ADR 0374 clause 1). func accountIsCovered(m catalogue.Manifest) bool { return catalogue.CarriesVaultSealed(m.Module) || m.Moved } // vaultInstalled says whether the vault is assigned to any machine. Until it is, as in genesis (ADR 0113 §15 to §18, // mesh-host's bootstrap, which issues the bus's and the provisioner's accounts before the vault step), there is no // vault to hand to: the value is kept in the controller's store as before, and the vault takes it afterwards by the // move (move-in takes a value of the controller's store with origin made, accepted or issued, as it is). Only a // vault that is installed and does not answer fails the issue. func vaultInstalled(ctx context.Context, inv *inventory.Inventory) (bool, error) { entries, err := inv.Catalogued(ctx) if err != nil { return false, err } for _, e := range entries { if e.Manifest.Module == "mesh-vault" && len(e.On) > 0 { return true, nil } } return false, nil } // handIssuedToVault hands the value just minted for module's own secret name on node to the vault, when the module's // accounts are covered, and does nothing otherwise. Loud when the vault does not take it: the bus's user list // already holds the new hash, so a vault that kept the old value would serve a password that no longer logs in. func handIssuedToVault(ctx context.Context, inv *inventory.Inventory, m catalogue.Manifest, node, name, held string) error { if !accountIsCovered(m) { return nil } if installed, err := vaultInstalled(ctx, inv); err != nil { return fmt.Errorf("whether the vault is installed cannot be read, so %s of %s was not handed to it: %w", name, m.Module, err) } else if !installed { return nil } target := ownSecretArgs(node, m.Module, name) target["origin"] = "issued" if _, err := acceptIntoVault(vaultAskerForIssue(ctx), target, held, "module issue"); err != nil { return fmt.Errorf("the credential is minted and kept here, and the bus's user list holds its hash, but the "+ "vault did not take %s of %s on %s: %w (`module issue` again hands a new one)", name, m.Module, node, err) } return nil }