mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-30 02:02:43 +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
	 Thy Ton
					Thy Ton