mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 01:32:33 +00:00
Fix mounts of external plugins that were registered before Vault v1.0.0 could not be tuned to use versioned plugins (#27881)
This commit is contained in:
4
changelog/27881.txt
Normal file
4
changelog/27881.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
```release-note:bug
|
||||
sys: Fix a bug where mounts of external plugins that were registered before Vault v1.0.0 could not be tuned to
|
||||
use versioned plugins.
|
||||
```
|
||||
@@ -2422,6 +2422,17 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
|
||||
pluginType = consts.PluginTypeCredential
|
||||
}
|
||||
|
||||
// Update MountEntry.Type of external plugins registered in Vault pre-v1.0.0 to the plugin binary name
|
||||
// stored in MountEntry.Config.PluginName
|
||||
// Previously, when upgrading Vault from pre-v1.0.0 to post-v1.0.0, MountEntry.Type of external plugins
|
||||
// remained "plugin" where it should follow the new scheme and be updated to the plugin binary name.
|
||||
// https://hashicorp.atlassian.net/browse/VAULT-21999
|
||||
if mountEntry.Config.PluginName != "" {
|
||||
if mountEntry.Config.PluginName != mountEntry.Type && mountEntry.Type == "plugin" {
|
||||
mountEntry.Type = mountEntry.Config.PluginName
|
||||
}
|
||||
}
|
||||
|
||||
pinnedVersion, err := b.Core.pluginCatalog.GetPinnedVersion(ctx, pluginType, mountEntry.Type)
|
||||
if err != nil && !errors.Is(err, pluginutil.ErrPinnedVersionNotFound) {
|
||||
return nil, err
|
||||
|
||||
@@ -2521,6 +2521,146 @@ func TestSystemBackend_tuneAuth(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSystemBackend_tune_updatePreV1MountEntryType tests once Vault is migrated post-v1.0.0,
|
||||
// the secret/auth mount was enabled in Vault pre-v1.0.0 has its MountEntry.Type updated
|
||||
// to the plugin name when tuned with plugin_version
|
||||
func TestSystemBackend_tune_updatePreV1MountEntryType(t *testing.T) {
|
||||
tempDir, err := filepath.EvalSymlinks(os.TempDir())
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
c, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{
|
||||
PluginDirectory: tempDir,
|
||||
})
|
||||
|
||||
ctx := namespace.RootContext(nil)
|
||||
testCases := []struct {
|
||||
pluginName string
|
||||
pluginType consts.PluginType
|
||||
mountTable string
|
||||
}{
|
||||
{"consul", consts.PluginTypeSecrets, "mounts"},
|
||||
{"approle", consts.PluginTypeCredential, "auth"},
|
||||
}
|
||||
|
||||
readMountConfig := func(pluginName, mountTable string) map[string]interface{} {
|
||||
t.Helper()
|
||||
req := logical.TestRequest(t, logical.ReadOperation, mountTable+"/"+pluginName)
|
||||
resp, err := c.systemBackend.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
return resp.Data
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
// Enable the mount
|
||||
{
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, tc.mountTable+"/"+tc.pluginName)
|
||||
req.Data["type"] = tc.pluginName
|
||||
|
||||
resp, err := c.systemBackend.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v, resp: %#v", err, resp)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
|
||||
config := readMountConfig(tc.pluginName, tc.mountTable)
|
||||
pluginVersion, ok := config["plugin_version"]
|
||||
if !ok || pluginVersion != "" {
|
||||
t.Fatalf("expected empty plugin version in config: %#v", config)
|
||||
}
|
||||
}
|
||||
|
||||
// Directly set MountEntry's Type to "plugin" and Config.PluginName like Vault pre-v1.0.0 does
|
||||
const mountEntryTypeExternalPlugin = "plugin"
|
||||
{
|
||||
var mountEntry *MountEntry
|
||||
if tc.mountTable == "mounts" {
|
||||
mountEntry, err = c.mounts.find(ctx, tc.pluginName+"/")
|
||||
} else {
|
||||
mountEntry, err = c.auth.find(ctx, tc.pluginName+"/")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mountEntry == nil {
|
||||
t.Fatal()
|
||||
}
|
||||
mountEntry.Type = mountEntryTypeExternalPlugin
|
||||
mountEntry.Config.PluginName = tc.pluginName
|
||||
err := c.persistMounts(ctx, c.mounts, &mountEntry.Local)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify MountEntry.Type is still "plugin" (Vault pre-v1.0.0)
|
||||
config := readMountConfig(tc.pluginName, tc.mountTable)
|
||||
mountEntryType, ok := config["type"]
|
||||
if !ok || mountEntryType != mountEntryTypeExternalPlugin {
|
||||
t.Fatalf("expected mount type %s but was %s, config: %#v", mountEntryTypeExternalPlugin, mountEntryType, config)
|
||||
}
|
||||
|
||||
// Register the plugin in the catalog, and then try the same request again.
|
||||
const externalPluginVersion string = "v0.0.7"
|
||||
{
|
||||
file, err := os.Create(filepath.Join(tempDir, tc.pluginName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := file.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = c.pluginCatalog.Set(context.Background(), pluginutil.SetPluginInput{
|
||||
Name: tc.pluginName,
|
||||
Type: tc.pluginType,
|
||||
Version: externalPluginVersion,
|
||||
Command: tc.pluginName,
|
||||
Args: []string{},
|
||||
Env: []string{},
|
||||
Sha256: []byte{},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tune mount with plugin_version
|
||||
{
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, tc.mountTable+"/"+tc.pluginName+"/tune")
|
||||
req.Data["plugin_version"] = externalPluginVersion
|
||||
|
||||
resp, err := c.systemBackend.HandleRequest(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v, resp: %#v", err, resp)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that plugin_version and MountEntry.Type were updated properly
|
||||
config = readMountConfig(tc.pluginName, tc.mountTable)
|
||||
pluginVersion, ok := config["plugin_version"]
|
||||
if !ok || pluginVersion == "" {
|
||||
t.Fatalf("expected non-empty plugin version in config: %#v", config)
|
||||
}
|
||||
if pluginVersion != externalPluginVersion {
|
||||
t.Fatalf("expected plugin version %#v, got %v", externalPluginVersion, pluginVersion)
|
||||
}
|
||||
|
||||
mountEntryType, ok = config["type"]
|
||||
if !ok || mountEntryType != tc.pluginName {
|
||||
t.Fatalf("expected mount type %s, got %s, config: %#v", tc.pluginName, mountEntryType, config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_policyList(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
req := logical.TestRequest(t, logical.ReadOperation, "policy")
|
||||
|
||||
Reference in New Issue
Block a user