A module's own secret rotates when its definition says the module reads it at start (hq 180)
`secret rotate <node> <module> <name>` makes the secret anew the way the first mint did, seals it
to the machine and the operator, and sends the machine, so the module starts again on the new value
— said in the log with who asked and when, never the value. Only for a secret whose definition says
`"taken": "at-start"`: an own secret is now a path, or {path, taken}, and a definition that says
nothing of how a secret is taken is refused with the word to write, because a credential rotated
under software that never reads it again is worse than one left alone (issue 179). `applied` is
refused by name until the staged form ADR 0114 decided is built; a value given to the mesh is
refused as ADR 0113 says. `rotate` is a verb on the controller's seat with two shapes — a pair
credential by provision, an own secret by machine, module and name — so the console can ask.
Registered manifests keep their bytes: a path alone is written back as a path.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"github.com/novox/mesh-controller/internal/catalogue"
|
||||
"github.com/novox/mesh-controller/internal/secrets"
|
||||
"strings"
|
||||
@@ -408,7 +409,7 @@ func TestACredentialGoesWhenEitherMachineDoes(t *testing.T) {
|
||||
func TestASecretTheMeshWasGivenIsNotReinventedWhenTheMachineRejoins(t *testing.T) {
|
||||
inv, ctx := twoNodesWithKeys(t)
|
||||
if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "builder", Version: "1",
|
||||
OwnSecrets: map[string]string{"broker": "/run/broker"}}, Source{}); err != nil {
|
||||
OwnSecrets: catalogue.OwnSecrets{"broker": {Path: "/run/broker"}}}, Source{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
const url = "amqps://builder:the-password-the-broker-was-told@broker/"
|
||||
@@ -440,7 +441,7 @@ func TestASecretTheMeshWasGivenIsNotReinventedWhenTheMachineRejoins(t *testing.T
|
||||
func TestASecretTheMeshWasGivenSurvivesAnOrdinaryPush(t *testing.T) {
|
||||
inv, ctx := twoNodesWithKeys(t)
|
||||
if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "builder", Version: "1",
|
||||
OwnSecrets: map[string]string{"broker": "/run/broker"}}, Source{}); err != nil {
|
||||
OwnSecrets: catalogue.OwnSecrets{"broker": {Path: "/run/broker"}}}, Source{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := inv.AcceptSecretForModule(ctx, "consumer", "builder", "broker",
|
||||
@@ -725,7 +726,7 @@ func TestTheOperatorRecoversEachLocalNameApart(t *testing.T) {
|
||||
func TestADeliveredSecretIsRefusedUnderANameTheModuleDoesNotDeclare(t *testing.T) {
|
||||
inv, ctx := twoNodesWithKeys(t)
|
||||
if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "step-ca", Version: "1",
|
||||
OwnSecrets: map[string]string{"password": "/run/password"}}, Source{}); err != nil {
|
||||
OwnSecrets: catalogue.OwnSecrets{"password": {Path: "/run/password"}}}, Source{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := inv.AcceptSecretForModule(ctx, "consumer", "step-ca", "root-key", "not-a-key")
|
||||
@@ -785,3 +786,60 @@ func TestADeliveredPairCredentialIsRefusedForARequirementTheModuleDoesNotHave(t
|
||||
t.Errorf("a delivery under a kept local was refused: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// A module's own secret rotates when its definition says the module reads it at start: made anew,
|
||||
// sealed to the machine and the operator, origin made. Refused with the reason when the definition
|
||||
// says nothing, says the module applies it, or when the value was given to the mesh (novox/hq
|
||||
// ADR 0114, issue 180).
|
||||
func TestAnOwnSecretRotatesOnlyWhenTheModuleReadsItAtStart(t *testing.T) {
|
||||
inv, ctx := twoNodesWithKeys(t)
|
||||
m := catalogue.Manifest{Module: "idp", Version: "1", OwnSecrets: catalogue.OwnSecrets{
|
||||
"session": {Path: "/var/lib/idp/session.secret", Taken: catalogue.TakenAtStart},
|
||||
"admin": {Path: "/var/lib/idp/admin.secret", Taken: catalogue.TakenApplied},
|
||||
"broker": {Path: "/var/lib/mesh/idp/broker"},
|
||||
}}
|
||||
if err := inv.RegisterModule(ctx, m, Source{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
before, err := inv.SecretForModule(ctx, "consumer", "idp", "session")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := inv.RotateModuleSecret(ctx, "consumer", "idp", "session"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
after, err := inv.SecretForModule(ctx, "consumer", "idp", "session")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if after == before {
|
||||
t.Fatal("rotating made no new value")
|
||||
}
|
||||
|
||||
if _, err := inv.SecretForModule(ctx, "consumer", "idp", "admin"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var refused ErrNotRotatable
|
||||
err = inv.RotateModuleSecret(ctx, "consumer", "idp", "admin")
|
||||
if !errors.As(err, &refused) || !strings.Contains(err.Error(), "staged") {
|
||||
t.Fatalf("an applied secret must be refused as not yet stageable: %v", err)
|
||||
}
|
||||
if _, err := inv.SecretForModule(ctx, "consumer", "idp", "broker"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = inv.RotateModuleSecret(ctx, "consumer", "idp", "broker")
|
||||
if !errors.As(err, &refused) || !strings.Contains(err.Error(), "does not say how it takes") {
|
||||
t.Fatalf("a secret that says nothing of how it is taken must be refused: %v", err)
|
||||
}
|
||||
|
||||
if err := inv.AcceptSecretForModule(ctx, "consumer", "idp", "session", "the-real-one"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = inv.RotateModuleSecret(ctx, "consumer", "idp", "session")
|
||||
if !errors.As(err, &refused) || !strings.Contains(err.Error(), "given to the mesh") {
|
||||
t.Fatalf("an accepted value must be refused: %v", err)
|
||||
}
|
||||
if err := inv.RotateModuleSecret(ctx, "consumer", "idp", "nothing"); err == nil || !strings.Contains(err.Error(), "does not declare") {
|
||||
t.Fatalf("an undeclared secret: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user