Let a node composing itself hand a module exactly when the vault judged its plan handed, through one rule (catalogue.AssignmentHands), so the vault and the node never judge postgres's secrets two ways again (issue 774)
This commit is contained in:
@@ -94,6 +94,15 @@ type SignersReader interface {
|
||||
VaultAuthority(ctx context.Context) string
|
||||
}
|
||||
|
||||
// HandedReader is a Reader that also says, of the composing node's modules, which the vault judged handed to the
|
||||
// provisioner when it answered OwnSecrets (the vault's `own`, its `handed`: catalogue.AssignmentHands of the plan in
|
||||
// each module's assignment). The node's composition then hands exactly those (compose.Node.Handed, issue 774), so the
|
||||
// vault and the node never judge one module two ways. Nil, or a Reader without it (a vault older than the field),
|
||||
// composes by the manifest and the machine, as before.
|
||||
type HandedReader interface {
|
||||
Handed(ctx context.Context, node string) map[string]bool
|
||||
}
|
||||
|
||||
// Mesh is what is true of the whole mesh and is no part's state on the bus yet: the private network's range and the
|
||||
// internal names' suffix as genesis was told them, and the mesh's authority certificate (public). Empty fields take
|
||||
// compose's defaults.
|
||||
@@ -408,6 +417,16 @@ func input(ctx context.Context, r Reader, mesh Mesh, s Scope, refuse func(module
|
||||
if in.OwnSecrets, err = r.OwnSecrets(ctx, s.Node); err != nil {
|
||||
return compose.Input{}, fmt.Errorf("frombus: the own secrets of %s's modules: %w", s.Node, err)
|
||||
}
|
||||
// And which of its modules the vault left out of that answer as handed: the node hands exactly those.
|
||||
if hr, ok := r.(HandedReader); ok {
|
||||
if handed := hr.Handed(ctx, s.Node); handed != nil {
|
||||
for i := range in.Nodes {
|
||||
if in.Nodes[i].Name == s.Node {
|
||||
in.Nodes[i].Handed = handed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The core's credentials travel as the vault's box sealed to the machine (ADR 0349 §16): the same values, which
|
||||
// the composition reads for a core module as its kept boxes.
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
// bus is a Reader over values held in memory, counting whose config values were read.
|
||||
type bus struct {
|
||||
vaultAuthority string
|
||||
handed map[string]bool
|
||||
placements map[string]delivery.Placement
|
||||
records map[string]delivery.NodeRecord
|
||||
modules map[string]delivery.Module
|
||||
@@ -79,6 +80,7 @@ func (b *bus) Placements(context.Context) (map[string]delivery.Placement, error)
|
||||
return b.placements, nil
|
||||
}
|
||||
func (b *bus) VaultAuthority(context.Context) string { return b.vaultAuthority }
|
||||
func (b *bus) Handed(context.Context, string) map[string]bool { return b.handed }
|
||||
func (b *bus) Records(context.Context) (map[string]delivery.NodeRecord, error) { return b.records, nil }
|
||||
func (b *bus) Modules(context.Context) (map[string]delivery.Module, error) { return b.modules, nil }
|
||||
func (b *bus) Manifest(_ context.Context, digest string) ([]byte, error) {
|
||||
@@ -245,6 +247,13 @@ func TestInput(t *testing.T) {
|
||||
bundled.Authority != "the mesh's certificate\nthe vault's certificate\n" {
|
||||
t.Errorf("the authority with the vault's published: %q, %v", bundled.Authority, err)
|
||||
}
|
||||
// Issue 774: the modules the vault judged handed when it answered own are the node's to hand, and no other node's.
|
||||
judged := mk()
|
||||
judged.handed = map[string]bool{"media": true, "xterm": false}
|
||||
if in, err := Input(ctx, judged, Mesh{}, Scope{Node: "laptop"}); err != nil ||
|
||||
!reflect.DeepEqual(in.Nodes[1].Handed, judged.handed) || in.Nodes[0].Handed != nil {
|
||||
t.Errorf("the vault's handed verdicts: %+v, %v", in.Nodes, err)
|
||||
}
|
||||
if !reflect.DeepEqual(b.valuesRead, []string{"laptop." + overlay.Name, "laptop.xterm", "laptop.media"}) {
|
||||
t.Errorf("laptop read config values %v; a node reads its own slice alone", b.valuesRead)
|
||||
}
|
||||
|
||||
@@ -142,6 +142,10 @@ type Node struct {
|
||||
Place Place
|
||||
// Assigned is the modules assigned to it, in the order the controller reads them (inv.Assigned).
|
||||
Assigned []string
|
||||
// Handed is, by module, whether the vault judged it handed to the provisioner when it answered this node's own
|
||||
// secrets (catalogue.AssignmentHands of the plan in its assignment): the node's own composition hands exactly those
|
||||
// (catalogue.Rendering.Assigned, issue 774). Nil where the vault said nothing of it, as for the controller.
|
||||
Handed map[string]bool
|
||||
// Capabilities are the ones present on it (inv.ProfileOf).
|
||||
Capabilities map[string]bool
|
||||
// PublicDomain is the domain it composes its routed names under (inv.PublicDomainOf).
|
||||
|
||||
@@ -65,7 +65,7 @@ func (c *composer) render(nodeName string, mode Mode) (Rendered, error) {
|
||||
}
|
||||
|
||||
// And each module's own secrets: a module handed to the provisioner has its secrets from the vault through the client.
|
||||
handing := catalogue.Rendering{Hands: r.Hands, Provisioner: r.Provisioner}
|
||||
handing := catalogue.Rendering{Hands: r.Hands, Provisioner: r.Provisioner, Assigned: r.Assigned}
|
||||
needed, foreseenOwn, err := c.ownSecretsFor(node, plan, handing, mode)
|
||||
if err != nil {
|
||||
return Rendered{}, err
|
||||
|
||||
@@ -73,6 +73,7 @@ func (c *composer) places(nodeName string, resolved Resolved) (Placed, error) {
|
||||
// not sent the field they would refuse.
|
||||
r.Hands = takesHanded(node)
|
||||
r.Provisioner = provisionerAccount(plan)
|
||||
r.Assigned = node.Handed
|
||||
r.ReadsHealth = node.Stated && node.Contract >= ReadinessContract
|
||||
r.JudgesRoot = node.Stated && node.Contract >= RootContract
|
||||
r.ReadsBusy = node.Stated && node.Contract >= BusyContract
|
||||
|
||||
Reference in New Issue
Block a user