Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect against version downgrade in secrets tune command #5788

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions command/secrets_tune_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,80 @@ func TestSecretsTuneCommand_Run(t *testing.T) {
}
})

t.Run("protect_downgrade", func(t *testing.T) {
t.Parallel()
client, closer := testVaultServer(t)
defer closer()

ui, cmd := testSecretsTuneCommand(t)
cmd.client = client

// Mount
if err := client.Sys().Mount("kv", &api.MountInput{
Type: "kv",
Options: map[string]string{
"version": "2",
},
}); err != nil {
t.Fatal(err)
}

// confirm default max_versions
mounts, err := client.Sys().ListMounts()
if err != nil {
t.Fatal(err)
}

mountInfo, ok := mounts["kv/"]
if !ok {
t.Fatalf("expected mount to exist")
}
if exp := "kv"; mountInfo.Type != exp {
t.Errorf("expected %q to be %q", mountInfo.Type, exp)
}
if exp := "2"; mountInfo.Options["version"] != exp {
t.Errorf("expected %q to be %q", mountInfo.Options["version"], exp)
}

if exp := ""; mountInfo.Options["max_versions"] != exp {
t.Errorf("expected %s to be empty", mountInfo.Options["max_versions"])
}

// omitting the version should not cause a downgrade
code := cmd.Run([]string{
"-options", "max_versions=2",
"kv/",
})
if exp := 0; code != exp {
t.Errorf("expected %d to be %d", code, exp)
}

expected := "Success! Tuned the secrets engine at: kv/"
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
if !strings.Contains(combined, expected) {
t.Errorf("expected %q to contain %q", combined, expected)
}

mounts, err = client.Sys().ListMounts()
if err != nil {
t.Fatal(err)
}

mountInfo, ok = mounts["kv/"]
if !ok {
t.Fatalf("expected mount to exist")
}
if exp := "2"; mountInfo.Options["version"] != exp {
t.Errorf("expected %q to be %q", mountInfo.Options["version"], exp)
}
if exp := "kv"; mountInfo.Type != exp {
t.Errorf("expected %q to be %q", mountInfo.Type, exp)
}
if exp := "2"; mountInfo.Options["max_versions"] != exp {
t.Errorf("expected %s to be %s", mountInfo.Options["max_versions"], exp)
}
})

t.Run("integration", func(t *testing.T) {
t.Run("flags_all", func(t *testing.T) {
t.Parallel()
Expand Down
9 changes: 9 additions & 0 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func systemBackendMemDBSchema() *memdb.DBSchema {
return systemSchema
}

// NewSystemBackend makes a new sys backend
func NewSystemBackend(core *Core, logger log.Logger) *SystemBackend {
db, _ := memdb.NewMemDB(systemBackendMemDBSchema())

Expand Down Expand Up @@ -1342,6 +1343,14 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
resp = &logical.Response{}
resp.AddWarning(fmt.Sprintf("Upgrading mount from version %d to version %d. This mount will be unavailable for a brief period and will resume service shortly.", meVersion, optVersion))
}
} else {
// if version is not included in the options, and is present in the
// current mountEntry's options, copy it's value to the new options map to
// protect against accidental version downgrades
if vers, ok := mountEntry.Options["version"]; ok {
options["version"] = vers
numBuiltIn++
}
}
if options != nil {
// For anything we don't recognize and provide special handling,
Expand Down