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:
@@ -227,19 +227,33 @@ func (i *Inventory) SecretForModule(ctx context.Context, node, module, name stri
|
||||
module, node, name, node)
|
||||
}
|
||||
|
||||
made, err := secrets.Make(key, key)
|
||||
operator, err := i.OperatorKey(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Sealed once, to one recipient. Make seals to two ends because a provision has two; here
|
||||
// both are the same machine, and only one copy is kept.
|
||||
var also []string
|
||||
if operator != "" {
|
||||
also = append(also, operator)
|
||||
}
|
||||
made, more, err := secrets.MakeAlso(key, key, also...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Sealed once to the machine — Make seals to two ends because a provision has two; here both
|
||||
// are the same machine, and only one copy is kept — and once more to the operator when the
|
||||
// mesh has one (novox/hq ADR 0085, amended), which is the copy a person can recover from.
|
||||
var forOperator, operatorKey *string
|
||||
if operator != "" {
|
||||
forOperator, operatorKey = &more[0], &operator
|
||||
}
|
||||
if _, err := i.store.Pool().Exec(ctx,
|
||||
`insert into module_secret (node, module, name, sealed, node_key, origin)
|
||||
values ($1, $2, $3, $4, $5, 'made')
|
||||
`insert into module_secret (node, module, name, sealed, node_key, origin, operator_sealed, operator_key)
|
||||
values ($1, $2, $3, $4, $5, 'made', $6, $7)
|
||||
on conflict (node, module, name) do update set
|
||||
sealed = excluded.sealed, node_key = excluded.node_key,
|
||||
origin = excluded.origin, made_at = now()`,
|
||||
record.ID, module, name, made.ForConsumer, key); err != nil {
|
||||
origin = excluded.origin, made_at = now(),
|
||||
operator_sealed = excluded.operator_sealed, operator_key = excluded.operator_key`,
|
||||
record.ID, module, name, made.ForConsumer, key, forOperator, operatorKey); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return made.ForConsumer, nil
|
||||
@@ -273,13 +287,28 @@ func (i *Inventory) AcceptSecretForModule(ctx context.Context, node, module, nam
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// And to the operator, when the mesh has one: a value a person supplied is the one a person
|
||||
// most needs to get back, since the mesh cannot make another (novox/hq ADR 0085, amended).
|
||||
operator, err := i.OperatorKey(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var forOperator, operatorKey *string
|
||||
if operator != "" {
|
||||
blob, err := secrets.Seal(operator, []byte(value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
forOperator, operatorKey = &blob, &operator
|
||||
}
|
||||
_, err = i.store.Pool().Exec(ctx,
|
||||
`insert into module_secret (node, module, name, sealed, node_key, origin)
|
||||
values ($1, $2, $3, $4, $5, 'accepted')
|
||||
`insert into module_secret (node, module, name, sealed, node_key, origin, operator_sealed, operator_key)
|
||||
values ($1, $2, $3, $4, $5, 'accepted', $6, $7)
|
||||
on conflict (node, module, name) do update set
|
||||
sealed = excluded.sealed, node_key = excluded.node_key,
|
||||
origin = excluded.origin, made_at = now()`,
|
||||
record.ID, module, name, sealed.ForConsumer, key)
|
||||
origin = excluded.origin, made_at = now(),
|
||||
operator_sealed = excluded.operator_sealed, operator_key = excluded.operator_key`,
|
||||
record.ID, module, name, sealed.ForConsumer, key, forOperator, operatorKey)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user