Archived
57/V2: The controller's secret verbs go to the vault for a module filled the new way (issue 675) #337
@@ -67,6 +67,9 @@ type deskGive struct {
|
||||
// nil keeps no record (a test that does not look). end closes it with how it ended.
|
||||
open func(node, module, name, desk string) (int64, error)
|
||||
end func(id int64, outcome string) error
|
||||
// vault, when set, is the path of a module whose secrets are filled the new way (vault_secrets.go): the vault
|
||||
// records the ask, holds its bounds and opens what is typed; open, end and accept are not used.
|
||||
vault vaultAsker
|
||||
}
|
||||
|
||||
// askedByName is the caller as the prompt names it: the first clause of what the bus said, in the characters
|
||||
@@ -133,6 +136,9 @@ func (d deskGive) give(node, module, name, desk string) (string, error) {
|
||||
"bus, where an agent may answer first (novox/hq ADR 0259 §10)", module, name, node, module, name)
|
||||
}
|
||||
}
|
||||
if d.vault != nil {
|
||||
return d.giveToVault(node, module, name, desk)
|
||||
}
|
||||
// The bounds, read and kept before anybody is asked to type (novox/hq ADR 0277): one open prompt per secret,
|
||||
// few an hour. How the ask ends is recorded whatever happens below.
|
||||
outcome := "failed"
|
||||
@@ -275,6 +281,11 @@ func askAtDesk(ctx context.Context, node, module, name, desk string) error {
|
||||
},
|
||||
announce: func(node, module, name, how string) error { return announceSecretGiven(ctx, node, module, name, how) },
|
||||
}
|
||||
// A module whose secrets are filled the new way is asked for by the vault (ADR 0349 clause 9); every other
|
||||
// keeps today's path (clause 17).
|
||||
if secretsOfTheVault(module) {
|
||||
d.vault = theVault(ctx)
|
||||
}
|
||||
words, err := d.give(node, module, name, desk)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -53,6 +53,10 @@ type issuedTaker struct {
|
||||
keep func(provision, provider, value string) (inventory.IssuedKept, error)
|
||||
record func(act link.HandAct) error
|
||||
send func(machines []string) error
|
||||
// ofTheVault says whether a provider module's secrets are filled the new way; for one that is, the value goes
|
||||
// into the vault (vault, vault_secrets.go) and nothing is kept, sealed or sent here. Nil is none.
|
||||
ofTheVault func(module string) bool
|
||||
vault vaultAsker
|
||||
}
|
||||
|
||||
// take asks every provider of the provision for its software's value and keeps each; it answers what it did, in
|
||||
@@ -90,6 +94,9 @@ func (t issuedTaker) take(provision string) (string, error) {
|
||||
|
||||
// takeFrom is one provider: asked, opened, kept, recorded and sent when it changed.
|
||||
func (t issuedTaker) takeFrom(provision string, p issuedProvider) (string, error) {
|
||||
if t.ofTheVault != nil && t.ofTheVault(p.Module) {
|
||||
return t.takeIntoVault(provision, p)
|
||||
}
|
||||
public, private, err := secrets.Keypair()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("no key could be made to take the value: %w", err)
|
||||
@@ -262,7 +269,9 @@ func secretIssued(ctx context.Context, args []string) error {
|
||||
return err
|
||||
})
|
||||
},
|
||||
send: func(machines []string) error { return sendTo(ctx, open, machines) },
|
||||
send: func(machines []string) error { return sendTo(ctx, open, machines) },
|
||||
ofTheVault: secretsOfTheVault,
|
||||
vault: theVault(ctx),
|
||||
}
|
||||
words, err := t.take(provision)
|
||||
if words != "" {
|
||||
|
||||
@@ -108,7 +108,12 @@ func secretCommand(ctx context.Context, args []string) error {
|
||||
if value == "" {
|
||||
return errors.New("there is nothing to seal")
|
||||
}
|
||||
return acceptForProvision(ctx, node, module, name, value)
|
||||
// The provider's module decides the path: filled the new way, the vault keeps the provision's credential.
|
||||
return bySwitch(module, secretsOfTheVault,
|
||||
func() error { return acceptForProvision(ctx, node, module, name, value) },
|
||||
func() error {
|
||||
return said(acceptIntoVault(theVault(ctx), provisionArgs(node, name), value, actingAs()))
|
||||
})
|
||||
}
|
||||
if *desk != "" {
|
||||
if *from != "" || *provider != "" {
|
||||
@@ -125,23 +130,50 @@ func secretCommand(ctx context.Context, args []string) error {
|
||||
if value == "" {
|
||||
return errors.New("there is nothing to seal")
|
||||
}
|
||||
return bySwitch(module, secretsOfTheVault,
|
||||
func() error { return acceptKept(ctx, node, module, name, *provider, *local, value) },
|
||||
func() error {
|
||||
// Sealed here to the vault's key for this one call; only the sealed box leaves this process.
|
||||
target := ownSecretArgs(node, module, name)
|
||||
if *provider != "" {
|
||||
if *local != "" {
|
||||
return errors.New("--local names a credential inside the module; the vault keeps one credential " +
|
||||
"per provider and provision, so it takes no --local: nothing was sealed")
|
||||
}
|
||||
target = provisionArgs(*provider, name)
|
||||
}
|
||||
return said(acceptIntoVault(theVault(ctx), target, value, actingAs()))
|
||||
})
|
||||
}
|
||||
|
||||
// said prints what was done, or answers why not.
|
||||
func said(words string, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(words)
|
||||
return nil
|
||||
}
|
||||
|
||||
// acceptKept is today's `secret accept`: the value sealed into the controller's store, for a module whose secrets
|
||||
// are filled the old way.
|
||||
func acceptKept(ctx context.Context, node, module, name, provider, local, value string) error {
|
||||
open, err := openStores(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer open.Close()
|
||||
|
||||
if *provider != "" {
|
||||
if provider != "" {
|
||||
// Into the pair, not into the module's own secrets: what the provider is asked to create
|
||||
// and what the consumer reads are the same value, and neither end can be told a different
|
||||
// one later without the other (novox/hq 04-ISSUES/070).
|
||||
if err := open.inventory.AcceptSecretForPair(ctx, name, node, module, *provider, *local, value); err != nil {
|
||||
if err := open.inventory.AcceptSecretForPair(ctx, name, node, module, provider, local, value); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s on %s now holds %q from %s%s, sealed to both machines.\n", module, node, name, *provider, asLocal(*local))
|
||||
fmt.Printf("%s on %s now holds %q from %s%s, sealed to both machines.\n", module, node, name, provider, asLocal(local))
|
||||
fmt.Printf(" the mesh cannot read it back, will not replace it with one of its own, and will not rotate it\n")
|
||||
fmt.Printf(" run `push %s` and `push %s` to send it\n", *provider, node)
|
||||
fmt.Printf(" run `push %s` and `push %s` to send it\n", provider, node)
|
||||
return nil
|
||||
}
|
||||
// A trusted party's secret is announced before it is kept (the confirmation review of 2026-10-09, N1-give):
|
||||
@@ -485,6 +517,22 @@ func secretRotate(ctx context.Context, args []string) error {
|
||||
return errors.New(secretUsage)
|
||||
}
|
||||
node, module, name := rest[0], rest[1], rest[2]
|
||||
return bySwitch(module, secretsOfTheVault,
|
||||
func() error { return rotateKept(ctx, node, module, name, why) },
|
||||
func() error {
|
||||
words, err := rotateInVault(theVault(ctx), ownSecretArgs(node, module, name), actingAs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
why.record(ctx, "secret rotate", []string{node, module, name})
|
||||
fmt.Println(words)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// rotateKept is today's `secret rotate`: made anew in the controller's store and sent, for a module whose
|
||||
// secrets are filled the old way.
|
||||
func rotateKept(ctx context.Context, node, module, name string, why handActFlags) error {
|
||||
open, err := openStores(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user