mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	AutoMTLS for secrets/auth plugins (#15671)
* use automtls for v5 secrets/auth plugins * add automtls env guard * start backend without metadata mode * use PluginClientConfig for backend's NewPluginClient param refactor * - fix pluginutil test - do not expect plugin to be unloaded in UT - fix pluginutil tests --need new env var - use require in UT - fix lazy load test * add changelog * prioritize automtls; improve comments * user multierror; refactor pluginSet for v4 unit test * add test cases for v4 and v5 plugin versions * remove unnecessary call to AutoMTLSSupported * update comment on pluginSets * use runconfig directly in sdk newpluginclient * use automtls without metadatamode for v5 backend plugin registration * use multierror for plugin runconfig calls * remove some unnecessary code
This commit is contained in:
		 John-Michael Faircloth
					John-Michael Faircloth
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							ba56224a2a
						
					
				
				
					commit
					39bcd5c715
				
			| @@ -17,6 +17,10 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// PluginAutoMTLSEnv ensures AutoMTLS is used. This overrides setting a | ||||
| 	// TLSProviderFunc for a plugin. | ||||
| 	PluginAutoMTLSEnv = "VAULT_PLUGIN_AUTOMTLS" | ||||
|  | ||||
| 	// PluginMetadataModeEnv is an ENV name used to disable TLS communication | ||||
| 	// to bootstrap mounting plugins. | ||||
| 	PluginMetadataModeEnv = "VAULT_PLUGIN_METADATA_MODE" | ||||
| @@ -120,7 +124,7 @@ func VaultPluginTLSProvider(apiTLSConfig *TLSConfig) func() (*tls.Config, error) | ||||
| // VaultPluginTLSProviderContext is run inside a plugin and retrieves the response | ||||
| // wrapped TLS certificate from vault. It returns a configured TLS Config. | ||||
| func VaultPluginTLSProviderContext(ctx context.Context, apiTLSConfig *TLSConfig) func() (*tls.Config, error) { | ||||
| 	if os.Getenv(PluginMetadataModeEnv) == "true" { | ||||
| 	if os.Getenv(PluginAutoMTLSEnv) == "true" || os.Getenv(PluginMetadataModeEnv) == "true" { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import ( | ||||
|  | ||||
| 	log "github.com/hashicorp/go-hclog" | ||||
|  | ||||
| 	"github.com/hashicorp/go-multierror" | ||||
| 	uuid "github.com/hashicorp/go-uuid" | ||||
| 	"github.com/hashicorp/vault/sdk/framework" | ||||
| 	"github.com/hashicorp/vault/sdk/helper/consts" | ||||
| @@ -51,17 +52,32 @@ func Backend(ctx context.Context, conf *logical.BackendConfig) (*PluginBackend, | ||||
|  | ||||
| 	sys := conf.System | ||||
|  | ||||
| 	// NewBackend with isMetadataMode set to true | ||||
| 	raw, err := bplugin.NewBackend(ctx, name, pluginType, sys, conf, true) | ||||
| 	merr := &multierror.Error{} | ||||
| 	// NewBackend with isMetadataMode set to false | ||||
| 	raw, err := bplugin.NewBackend(ctx, name, pluginType, sys, conf, false, true) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		merr = multierror.Append(merr, err) | ||||
| 		// NewBackend with isMetadataMode set to true | ||||
| 		raw, err = bplugin.NewBackend(ctx, name, pluginType, sys, conf, true, false) | ||||
| 		if err != nil { | ||||
| 			merr = multierror.Append(merr, err) | ||||
| 			return nil, merr | ||||
| 		} | ||||
| 	} else { | ||||
| 		b.Backend = raw | ||||
| 		b.config = conf | ||||
| 		b.loaded = true | ||||
| 		b.autoMTLSSupported = true | ||||
|  | ||||
| 		return &b, nil | ||||
| 	} | ||||
|  | ||||
| 	// Setup the backend so we can inspect the SpecialPaths and Type | ||||
| 	err = raw.Setup(ctx, conf) | ||||
| 	if err != nil { | ||||
| 		raw.Cleanup(ctx) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// Get SpecialPaths and BackendType | ||||
| 	paths := raw.SpecialPaths() | ||||
| 	btype := raw.Type() | ||||
|  | ||||
| @@ -85,6 +101,7 @@ type PluginBackend struct { | ||||
| 	Backend logical.Backend | ||||
| 	sync.RWMutex | ||||
|  | ||||
| 	autoMTLSSupported bool | ||||
| 	config            *logical.BackendConfig | ||||
|  | ||||
| 	// Used to detect if we already reloaded | ||||
| @@ -105,7 +122,7 @@ func (b *PluginBackend) startBackend(ctx context.Context, storage logical.Storag | ||||
| 	// Ensure proper cleanup of the backend (i.e. call client.Kill()) | ||||
| 	b.Backend.Cleanup(ctx) | ||||
|  | ||||
| 	nb, err := bplugin.NewBackend(ctx, pluginName, pluginType, b.config.System, b.config, false) | ||||
| 	nb, err := bplugin.NewBackend(ctx, pluginName, pluginType, b.config.System, b.config, false, b.autoMTLSSupported) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|   | ||||
| @@ -59,7 +59,7 @@ func testLazyLoad(t *testing.T, methodWrapper func() error) *PluginBackend { | ||||
| 	} | ||||
|  | ||||
| 	// this is a dummy plugin that hasn't really been loaded yet | ||||
| 	orig, err := plugin.NewBackend(ctx, "test-plugin", consts.PluginTypeSecrets, sysView, config, true) | ||||
| 	orig, err := plugin.NewBackend(ctx, "test-plugin", consts.PluginTypeSecrets, sysView, config, true, false) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										3
									
								
								changelog/15671.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/15671.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| ```release-note:improvement | ||||
| plugins: Use AutoMTLS for secrets engines and auth methods run as external plugins. | ||||
| ``` | ||||
| @@ -8,6 +8,10 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// PluginAutoMTLSEnv is used to ensure AutoMTLS is used. This will override | ||||
| 	// setting a TLSProviderFunc for a plugin. | ||||
| 	PluginAutoMTLSEnv = "VAULT_PLUGIN_AUTOMTLS" | ||||
|  | ||||
| 	// PluginMlockEnabled is the ENV name used to pass the configuration for | ||||
| 	// enabling mlock | ||||
| 	PluginMlockEnabled = "VAULT_PLUGIN_MLOCK_ENABLED" | ||||
|   | ||||
| @@ -9,6 +9,8 @@ import ( | ||||
| 	status "google.golang.org/grpc/status" | ||||
| ) | ||||
|  | ||||
| const MultiplexingCtxKey string = "multiplex_id" | ||||
|  | ||||
| type PluginMultiplexingServerImpl struct { | ||||
| 	UnimplementedPluginMultiplexingServer | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,7 @@ type PluginClientConfig struct { | ||||
| 	IsMetadataMode  bool | ||||
| 	AutoMTLS        bool | ||||
| 	MLock           bool | ||||
| 	Wrapper         RunnerUtil | ||||
| } | ||||
|  | ||||
| type runConfig struct { | ||||
| @@ -33,8 +34,6 @@ type runConfig struct { | ||||
| 	// Initialized with what's in PluginRunner.Env, but can be added to | ||||
| 	env []string | ||||
|  | ||||
| 	wrapper RunnerUtil | ||||
|  | ||||
| 	PluginClientConfig | ||||
| } | ||||
|  | ||||
| @@ -43,7 +42,7 @@ func (rc runConfig) makeConfig(ctx context.Context) (*plugin.ClientConfig, error | ||||
| 	cmd.Env = append(cmd.Env, rc.env...) | ||||
|  | ||||
| 	// Add the mlock setting to the ENV of the plugin | ||||
| 	if rc.MLock || (rc.wrapper != nil && rc.wrapper.MlockEnabled()) { | ||||
| 	if rc.MLock || (rc.Wrapper != nil && rc.Wrapper.MlockEnabled()) { | ||||
| 		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMlockEnabled, "true")) | ||||
| 	} | ||||
| 	cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version)) | ||||
| @@ -54,6 +53,9 @@ func (rc runConfig) makeConfig(ctx context.Context) (*plugin.ClientConfig, error | ||||
| 	metadataEnv := fmt.Sprintf("%s=%t", PluginMetadataModeEnv, rc.IsMetadataMode) | ||||
| 	cmd.Env = append(cmd.Env, metadataEnv) | ||||
|  | ||||
| 	automtlsEnv := fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, rc.AutoMTLS) | ||||
| 	cmd.Env = append(cmd.Env, automtlsEnv) | ||||
|  | ||||
| 	var clientTLSConfig *tls.Config | ||||
| 	if !rc.AutoMTLS && !rc.IsMetadataMode { | ||||
| 		// Get a CA TLS Certificate | ||||
| @@ -70,7 +72,7 @@ func (rc runConfig) makeConfig(ctx context.Context) (*plugin.ClientConfig, error | ||||
|  | ||||
| 		// Use CA to sign a server cert and wrap the values in a response wrapped | ||||
| 		// token. | ||||
| 		wrapToken, err := wrapServerConfig(ctx, rc.wrapper, certBytes, key) | ||||
| 		wrapToken, err := wrapServerConfig(ctx, rc.Wrapper, certBytes, key) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -120,7 +122,7 @@ func Env(env ...string) RunOpt { | ||||
|  | ||||
| func Runner(wrapper RunnerUtil) RunOpt { | ||||
| 	return func(rc *runConfig) { | ||||
| 		rc.wrapper = wrapper | ||||
| 		rc.Wrapper = wrapper | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os/exec" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| @@ -14,6 +13,7 @@ import ( | ||||
| 	"github.com/hashicorp/go-plugin" | ||||
| 	"github.com/hashicorp/vault/sdk/helper/wrapping" | ||||
| 	"github.com/stretchr/testify/mock" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | ||||
| func TestMakeConfig(t *testing.T) { | ||||
| @@ -78,6 +78,7 @@ func TestMakeConfig(t *testing.T) { | ||||
| 						"initial=true", | ||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), | ||||
| 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, false), | ||||
| 					}, | ||||
| 				), | ||||
| 				SecureConfig: &plugin.SecureConfig{ | ||||
| @@ -143,6 +144,7 @@ func TestMakeConfig(t *testing.T) { | ||||
| 						fmt.Sprintf("%s=%t", PluginMlockEnabled, true), | ||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), | ||||
| 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, false), | ||||
| 						fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, "testtoken"), | ||||
| 					}, | ||||
| 				), | ||||
| @@ -205,6 +207,7 @@ func TestMakeConfig(t *testing.T) { | ||||
| 						"initial=true", | ||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), | ||||
| 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, true), | ||||
| 					}, | ||||
| 				), | ||||
| 				SecureConfig: &plugin.SecureConfig{ | ||||
| @@ -266,6 +269,7 @@ func TestMakeConfig(t *testing.T) { | ||||
| 						"initial=true", | ||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), | ||||
| 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, true), | ||||
| 					}, | ||||
| 				), | ||||
| 				SecureConfig: &plugin.SecureConfig{ | ||||
| @@ -290,7 +294,7 @@ func TestMakeConfig(t *testing.T) { | ||||
| 				Return(test.responseWrapInfo, test.responseWrapInfoErr) | ||||
| 			mockWrapper.On("MlockEnabled"). | ||||
| 				Return(test.mlockEnabled) | ||||
| 			test.rc.wrapper = mockWrapper | ||||
| 			test.rc.Wrapper = mockWrapper | ||||
| 			defer mockWrapper.AssertNumberOfCalls(t, "ResponseWrapData", test.responseWrapInfoTimes) | ||||
| 			defer mockWrapper.AssertNumberOfCalls(t, "MlockEnabled", test.mlockEnabledTimes) | ||||
|  | ||||
| @@ -318,9 +322,7 @@ func TestMakeConfig(t *testing.T) { | ||||
| 			} | ||||
| 			config.TLSConfig = nil | ||||
|  | ||||
| 			if !reflect.DeepEqual(config, test.expectedConfig) { | ||||
| 				t.Fatalf("Actual config: %#v\nExpected config: %#v", config, test.expectedConfig) | ||||
| 			} | ||||
| 			require.Equal(t, config, test.expectedConfig) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -38,8 +38,6 @@ type PluginClient interface { | ||||
| 	plugin.ClientProtocol | ||||
| } | ||||
|  | ||||
| const MultiplexingCtxKey string = "multiplex_id" | ||||
|  | ||||
| // PluginRunner defines the metadata needed to run a plugin securely with | ||||
| // go-plugin. | ||||
| type PluginRunner struct { | ||||
|   | ||||
| @@ -22,6 +22,7 @@ var ( | ||||
| type GRPCBackendPlugin struct { | ||||
| 	Factory           logical.Factory | ||||
| 	MetadataMode      bool | ||||
| 	AutoMTLSSupported bool | ||||
| 	Logger            log.Logger | ||||
|  | ||||
| 	// Embeding this will disable the netRPC protocol | ||||
| @@ -46,7 +47,8 @@ func (b *GRPCBackendPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCB | ||||
| 		broker:     broker, | ||||
| 		cleanupCh:  make(chan struct{}), | ||||
| 		doneCtx:    ctx, | ||||
| 		metadataMode: b.MetadataMode, | ||||
| 		// Only run in metadata mode if mode is true and autoMTLS is not supported | ||||
| 		metadataMode: b.MetadataMode && !b.AutoMTLSSupported, | ||||
| 	} | ||||
|  | ||||
| 	// Create the value and set the type | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/hashicorp/errwrap" | ||||
| 	log "github.com/hashicorp/go-hclog" | ||||
| 	plugin "github.com/hashicorp/go-plugin" | ||||
| 	"github.com/hashicorp/vault/sdk/helper/consts" | ||||
| 	"github.com/hashicorp/vault/sdk/helper/pluginutil" | ||||
| @@ -35,7 +34,7 @@ func (b *BackendPluginClient) Cleanup(ctx context.Context) { | ||||
| // external plugins, or a concrete implementation of the backend if it is a builtin backend. | ||||
| // The backend is returned as a logical.Backend interface. The isMetadataMode param determines whether | ||||
| // the plugin should run in metadata mode. | ||||
| func NewBackend(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool) (logical.Backend, error) { | ||||
| func NewBackend(ctx context.Context, pluginName string, pluginType consts.PluginType, sys pluginutil.LookRunnerUtil, conf *logical.BackendConfig, isMetadataMode bool, autoMTLS bool) (logical.Backend, error) { | ||||
| 	// Look for plugin in the plugin catalog | ||||
| 	pluginRunner, err := sys.LookupPlugin(ctx, pluginName, pluginType) | ||||
| 	if err != nil { | ||||
| @@ -59,8 +58,16 @@ func NewBackend(ctx context.Context, pluginName string, pluginType consts.Plugin | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		config := pluginutil.PluginClientConfig{ | ||||
| 			Name:           pluginName, | ||||
| 			PluginType:     pluginType, | ||||
| 			Logger:         conf.Logger.Named(pluginName), | ||||
| 			IsMetadataMode: isMetadataMode, | ||||
| 			AutoMTLS:       autoMTLS, | ||||
| 			Wrapper:        sys, | ||||
| 		} | ||||
| 		// create a backendPluginClient instance | ||||
| 		backend, err = NewPluginClient(ctx, sys, pluginRunner, conf.Logger, isMetadataMode) | ||||
| 		backend, err = NewPluginClient(ctx, pluginRunner, config) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -69,34 +76,49 @@ func NewBackend(ctx context.Context, pluginName string, pluginType consts.Plugin | ||||
| 	return backend, nil | ||||
| } | ||||
|  | ||||
| func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger, isMetadataMode bool) (logical.Backend, error) { | ||||
| 	// pluginMap is the map of plugins we can dispense. | ||||
| 	pluginSet := map[int]plugin.PluginSet{ | ||||
| // pluginSet returns the go-plugin PluginSet that we can dispense. This ensures | ||||
| // that plugins that don't support AutoMTLS are run on the appropriate version. | ||||
| func pluginSet(autoMTLS, metadataMode bool) map[int]plugin.PluginSet { | ||||
| 	if autoMTLS { | ||||
| 		return map[int]plugin.PluginSet{ | ||||
| 			5: { | ||||
| 				"backend": &GRPCBackendPlugin{ | ||||
| 					MetadataMode:      false, | ||||
| 					AutoMTLSSupported: true, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| 	return map[int]plugin.PluginSet{ | ||||
| 		// Version 3 used to supports both protocols. We want to keep it around | ||||
| 		// since it's possible old plugins built against this version will still | ||||
| 		// work with gRPC. There is currently no difference between version 3 | ||||
| 		// and version 4. | ||||
| 		3: { | ||||
| 			"backend": &GRPCBackendPlugin{ | ||||
| 				MetadataMode: isMetadataMode, | ||||
| 				MetadataMode: metadataMode, | ||||
| 			}, | ||||
| 		}, | ||||
| 		4: { | ||||
| 			"backend": &GRPCBackendPlugin{ | ||||
| 				MetadataMode: isMetadataMode, | ||||
| 				MetadataMode: metadataMode, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	namedLogger := logger.Named(pluginRunner.Name) | ||||
|  | ||||
| 	var client *plugin.Client | ||||
| 	var err error | ||||
| 	if isMetadataMode { | ||||
| 		client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginSet, handshakeConfig, []string{}, namedLogger) | ||||
| 	} else { | ||||
| 		client, err = pluginRunner.Run(ctx, sys, pluginSet, handshakeConfig, []string{}, namedLogger) | ||||
| } | ||||
|  | ||||
| func NewPluginClient(ctx context.Context, pluginRunner *pluginutil.PluginRunner, config pluginutil.PluginClientConfig) (logical.Backend, error) { | ||||
| 	ps := pluginSet(config.AutoMTLS, config.IsMetadataMode) | ||||
|  | ||||
| 	client, err := pluginRunner.RunConfig(ctx, | ||||
| 		pluginutil.Runner(config.Wrapper), | ||||
| 		pluginutil.PluginSets(ps), | ||||
| 		pluginutil.HandshakeConfig(handshakeConfig), | ||||
| 		pluginutil.Env(), | ||||
| 		pluginutil.Logger(config.Logger), | ||||
| 		pluginutil.MetadataMode(config.IsMetadataMode), | ||||
| 		pluginutil.AutoMTLS(config.AutoMTLS), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -126,9 +148,9 @@ func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunne | ||||
| 	} | ||||
|  | ||||
| 	// Wrap the backend in a tracing middleware | ||||
| 	if namedLogger.IsTrace() { | ||||
| 	if config.Logger.IsTrace() { | ||||
| 		backend = &backendTracingMiddleware{ | ||||
| 			logger: namedLogger.With("transport", transport), | ||||
| 			logger: config.Logger.With("transport", transport), | ||||
| 			next:   backend, | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -37,12 +37,13 @@ func Serve(opts *ServeOpts) error { | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// pluginMap is the map of plugins we can dispense. | ||||
| 	// pluginSets is the map of plugins we can dispense. | ||||
| 	pluginSets := map[int]plugin.PluginSet{ | ||||
| 		// Version 3 used to supports both protocols. We want to keep it around | ||||
| 		// since it's possible old plugins built against this version will still | ||||
| 		// work with gRPC. There is currently no difference between version 3 | ||||
| 		// and version 4. | ||||
| 		// AutoMTLS is not supported by versions lower than 5. | ||||
| 		3: { | ||||
| 			"backend": &GRPCBackendPlugin{ | ||||
| 				Factory: opts.BackendFactoryFunc, | ||||
| @@ -55,6 +56,13 @@ func Serve(opts *ServeOpts) error { | ||||
| 				Logger:  logger, | ||||
| 			}, | ||||
| 		}, | ||||
| 		5: { | ||||
| 			"backend": &GRPCBackendPlugin{ | ||||
| 				Factory:           opts.BackendFactoryFunc, | ||||
| 				Logger:            logger, | ||||
| 				AutoMTLSSupported: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	err := pluginutil.OptionallyEnableMlock() | ||||
|   | ||||
| @@ -31,8 +31,33 @@ const ( | ||||
| 	expectedEnvValue = "BAR" | ||||
| ) | ||||
|  | ||||
| // logicalVersionMap is a map of version to test plugin | ||||
| var logicalVersionMap = map[string]string{ | ||||
| 	"v4": "TestBackend_PluginMain_V4_Logical", | ||||
| 	"v5": "TestBackend_PluginMainLogical", | ||||
| } | ||||
|  | ||||
| // credentialVersionMap is a map of version to test plugin | ||||
| var credentialVersionMap = map[string]string{ | ||||
| 	"v4": "TestBackend_PluginMain_V4_Credentials", | ||||
| 	"v5": "TestBackend_PluginMainCredentials", | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_secret(t *testing.T) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -67,10 +92,25 @@ func TestSystemBackend_Plugin_secret(t *testing.T) { | ||||
| 				// If it fails, it means unseal process failed | ||||
| 				vault.TestWaitActive(t, core.Core) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_auth(t *testing.T) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, logical.TypeCredential) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeCredential, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -105,10 +145,25 @@ func TestSystemBackend_Plugin_auth(t *testing.T) { | ||||
| 				// If it fails, it means unseal process failed | ||||
| 				vault.TestWaitActive(t, core.Core) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_MissingBinary(t *testing.T) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -146,10 +201,25 @@ func TestSystemBackend_Plugin_MissingBinary(t *testing.T) { | ||||
| 			if err == nil { | ||||
| 				t.Fatalf("expected error") | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_MismatchType(t *testing.T) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -168,28 +238,43 @@ func TestSystemBackend_Plugin_MismatchType(t *testing.T) { | ||||
|  | ||||
| 			// Sleep a bit before cleanup is called | ||||
| 			time.Sleep(1 * time.Second) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_CatalogRemoved(t *testing.T) { | ||||
| 	t.Run("secret", func(t *testing.T) { | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeLogical, false) | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeLogical, false, logicalVersionMap) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("auth", func(t *testing.T) { | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeCredential, false) | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeCredential, false, credentialVersionMap) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("secret-mount-existing", func(t *testing.T) { | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeLogical, true) | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeLogical, true, logicalVersionMap) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("auth-mount-existing", func(t *testing.T) { | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeCredential, true) | ||||
| 		testPlugin_CatalogRemoved(t, logical.TypeCredential, true, credentialVersionMap) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMount bool) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, btype) | ||||
| func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMount bool, versionMap map[string]string) { | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -230,13 +315,13 @@ func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMoun | ||||
| 				switch btype { | ||||
| 				case logical.TypeLogical: | ||||
| 					// Add plugin back to the catalog | ||||
| 			vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainLogical", []string{}, "") | ||||
| 					vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, logicalVersionMap[tc.pluginVersion], []string{}, "") | ||||
| 					_, err = core.Client.Logical().Write("sys/mounts/mock-0", map[string]interface{}{ | ||||
| 						"type": "test", | ||||
| 					}) | ||||
| 				case logical.TypeCredential: | ||||
| 					// Add plugin back to the catalog | ||||
| 			vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, "") | ||||
| 					vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, credentialVersionMap[tc.pluginVersion], []string{}, "") | ||||
| 					_, err = core.Client.Logical().Write("sys/auth/mock-0", map[string]interface{}{ | ||||
| 						"type": "test", | ||||
| 					}) | ||||
| @@ -245,6 +330,8 @@ func testPlugin_CatalogRemoved(t *testing.T, btype logical.BackendType, testMoun | ||||
| 					t.Fatal("expected error when mounting on existing path") | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_continueOnError(t *testing.T) { | ||||
| @@ -278,7 +365,20 @@ func TestSystemBackend_Plugin_continueOnError(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func testPlugin_continueOnError(t *testing.T, btype logical.BackendType, mismatch bool, mountPoint string, pluginType consts.PluginType) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, btype) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, btype, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -296,18 +396,6 @@ func testPlugin_continueOnError(t *testing.T, btype logical.BackendType, mismatc | ||||
| 				t.Fatal("invalid command") | ||||
| 			} | ||||
|  | ||||
| 	// Mount credential type plugins | ||||
| 	switch btype { | ||||
| 	case logical.TypeCredential: | ||||
| 		vault.TestAddTestPlugin(t, core.Core, mountPoint, consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, cluster.TempDir) | ||||
| 		_, err = core.Client.Logical().Write(fmt.Sprintf("sys/auth/%s", mountPoint), map[string]interface{}{ | ||||
| 			"type": "mock-plugin", | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("err:%v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 			// Trigger a sha256 mismatch or missing plugin error | ||||
| 			if mismatch { | ||||
| 				req = logical.TestRequest(t, logical.UpdateOperation, fmt.Sprintf("sys/plugins/catalog/%s/mock-plugin", pluginType)) | ||||
| @@ -351,9 +439,11 @@ func testPlugin_continueOnError(t *testing.T, btype logical.BackendType, mismatc | ||||
| 			// Re-add the plugin to the catalog | ||||
| 			switch btype { | ||||
| 			case logical.TypeLogical: | ||||
| 		vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainLogical", []string{}, cluster.TempDir) | ||||
| 				plugin := logicalVersionMap[tc.pluginVersion] | ||||
| 				vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, plugin, []string{}, cluster.TempDir) | ||||
| 			case logical.TypeCredential: | ||||
| 		vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, cluster.TempDir) | ||||
| 				plugin := credentialVersionMap[tc.pluginVersion] | ||||
| 				vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, plugin, []string{}, cluster.TempDir) | ||||
| 			} | ||||
|  | ||||
| 			// Reload the plugin | ||||
| @@ -385,10 +475,25 @@ func testPlugin_continueOnError(t *testing.T, btype logical.BackendType, mismatc | ||||
| 			if resp == nil { | ||||
| 				t.Fatalf("bad: response should not be nil") | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_autoReload(t *testing.T) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -426,10 +531,25 @@ func TestSystemBackend_Plugin_autoReload(t *testing.T) { | ||||
| 			if resp.Data["value"].(string) == "baz" { | ||||
| 				t.Fatal("did not expect backend internal value to be 'baz'") | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_SealUnseal(t *testing.T) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 1, logical.TypeLogical, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			// Seal the cluster | ||||
| @@ -452,6 +572,8 @@ func TestSystemBackend_Plugin_SealUnseal(t *testing.T) { | ||||
| 			// Wait for active so post-unseal takes place | ||||
| 			// If it fails, it means unseal process failed | ||||
| 			vault.TestWaitActive(t, cluster.Cores[0].Core) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSystemBackend_Plugin_reload(t *testing.T) { | ||||
| @@ -498,7 +620,20 @@ func TestSystemBackend_Plugin_reload(t *testing.T) { | ||||
|  | ||||
| // Helper func to test different reload methods on plugin reload endpoint | ||||
| func testSystemBackend_PluginReload(t *testing.T, reqData map[string]interface{}, backendType logical.BackendType) { | ||||
| 	cluster := testSystemBackendMock(t, 1, 2, backendType) | ||||
| 	testCases := []struct { | ||||
| 		pluginVersion string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			pluginVersion: "v5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			pluginVersion: "v4", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.pluginVersion, func(t *testing.T) { | ||||
| 			cluster := testSystemBackendMock(t, 1, 2, backendType, tc.pluginVersion) | ||||
| 			defer cluster.Cleanup() | ||||
|  | ||||
| 			core := cluster.Cores[0] | ||||
| @@ -546,6 +681,8 @@ func testSystemBackend_PluginReload(t *testing.T, reqData map[string]interface{} | ||||
| 					t.Fatal("did not expect backend internal value to be 'baz'") | ||||
| 				} | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // testSystemBackendMock returns a systemBackend with the desired number | ||||
| @@ -553,7 +690,7 @@ func testSystemBackend_PluginReload(t *testing.T, reqData map[string]interface{} | ||||
| // ways of providing the plugin_name. | ||||
| // | ||||
| // The mounts are mounted at sys/mounts/mock-[numMounts] or sys/auth/mock-[numMounts] | ||||
| func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType logical.BackendType) *vault.TestCluster { | ||||
| func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType logical.BackendType, pluginVersion string) *vault.TestCluster { | ||||
| 	coreConfig := &vault.CoreConfig{ | ||||
| 		LogicalBackends: map[string]logical.Factory{ | ||||
| 			"plugin": plugin.Factory, | ||||
| @@ -585,7 +722,8 @@ func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType lo | ||||
|  | ||||
| 	switch backendType { | ||||
| 	case logical.TypeLogical: | ||||
| 		vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, "TestBackend_PluginMainLogical", []string{}, tempDir) | ||||
| 		plugin := logicalVersionMap[pluginVersion] | ||||
| 		vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeSecrets, plugin, []string{}, tempDir) | ||||
| 		for i := 0; i < numMounts; i++ { | ||||
| 			// Alternate input styles for plugin_name on every other mount | ||||
| 			options := map[string]interface{}{ | ||||
| @@ -600,7 +738,8 @@ func testSystemBackendMock(t *testing.T, numCores, numMounts int, backendType lo | ||||
| 			} | ||||
| 		} | ||||
| 	case logical.TypeCredential: | ||||
| 		vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, "TestBackend_PluginMainCredentials", []string{}, tempDir) | ||||
| 		plugin := credentialVersionMap[pluginVersion] | ||||
| 		vault.TestAddTestPlugin(t, core.Core, "mock-plugin", consts.PluginTypeCredential, plugin, []string{}, tempDir) | ||||
| 		for i := 0; i < numMounts; i++ { | ||||
| 			// Alternate input styles for plugin_name on every other mount | ||||
| 			options := map[string]interface{}{ | ||||
| @@ -671,9 +810,15 @@ func testSystemBackend_SingleCluster_Env(t *testing.T, env []string) *vault.Test | ||||
| 	return cluster | ||||
| } | ||||
|  | ||||
| func TestBackend_PluginMainLogical(t *testing.T) { | ||||
| func TestBackend_PluginMain_V4_Logical(t *testing.T) { | ||||
| 	args := []string{} | ||||
| 	if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { | ||||
| 	// don't run as a standalone unit test | ||||
| 	if os.Getenv(pluginutil.PluginVaultVersionEnv) == "" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// don't run as a V5 plugin | ||||
| 	if os.Getenv(pluginutil.PluginAutoMTLSEnv) == "true" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -686,6 +831,8 @@ func TestBackend_PluginMainLogical(t *testing.T) { | ||||
| 	apiClientMeta := &api.PluginAPIClientMeta{} | ||||
| 	flags := apiClientMeta.FlagSet() | ||||
| 	flags.Parse(args) | ||||
|  | ||||
| 	// V4 does not support AutoMTLS so we set a TLSConfig via TLSProviderFunc | ||||
| 	tlsConfig := apiClientMeta.GetTLSConfig() | ||||
| 	tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) | ||||
|  | ||||
| @@ -700,9 +847,9 @@ func TestBackend_PluginMainLogical(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestBackend_PluginMainCredentials(t *testing.T) { | ||||
| func TestBackend_PluginMainLogical(t *testing.T) { | ||||
| 	args := []string{} | ||||
| 	if os.Getenv(pluginutil.PluginUnwrapTokenEnv) == "" && os.Getenv(pluginutil.PluginMetadataModeEnv) != "true" { | ||||
| 	if os.Getenv(pluginutil.PluginVaultVersionEnv) == "" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -715,6 +862,40 @@ func TestBackend_PluginMainCredentials(t *testing.T) { | ||||
| 	apiClientMeta := &api.PluginAPIClientMeta{} | ||||
| 	flags := apiClientMeta.FlagSet() | ||||
| 	flags.Parse(args) | ||||
|  | ||||
| 	factoryFunc := mock.FactoryType(logical.TypeLogical) | ||||
|  | ||||
| 	err := lplugin.Serve(&lplugin.ServeOpts{ | ||||
| 		BackendFactoryFunc: factoryFunc, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestBackend_PluginMain_V4_Credentials(t *testing.T) { | ||||
| 	args := []string{} | ||||
| 	// don't run as a standalone unit test | ||||
| 	if os.Getenv(pluginutil.PluginVaultVersionEnv) == "" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// don't run as a V5 plugin | ||||
| 	if os.Getenv(pluginutil.PluginAutoMTLSEnv) == "true" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv) | ||||
| 	if caPEM == "" { | ||||
| 		t.Fatal("CA cert not passed in") | ||||
| 	} | ||||
| 	args = append(args, fmt.Sprintf("--ca-cert=%s", caPEM)) | ||||
|  | ||||
| 	apiClientMeta := &api.PluginAPIClientMeta{} | ||||
| 	flags := apiClientMeta.FlagSet() | ||||
| 	flags.Parse(args) | ||||
|  | ||||
| 	// V4 does not support AutoMTLS so we set a TLSConfig via TLSProviderFunc | ||||
| 	tlsConfig := apiClientMeta.GetTLSConfig() | ||||
| 	tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) | ||||
|  | ||||
| @@ -729,6 +910,32 @@ func TestBackend_PluginMainCredentials(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestBackend_PluginMainCredentials(t *testing.T) { | ||||
| 	args := []string{} | ||||
| 	if os.Getenv(pluginutil.PluginVaultVersionEnv) == "" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	caPEM := os.Getenv(pluginutil.PluginCACertPEMEnv) | ||||
| 	if caPEM == "" { | ||||
| 		t.Fatal("CA cert not passed in") | ||||
| 	} | ||||
| 	args = append(args, fmt.Sprintf("--ca-cert=%s", caPEM)) | ||||
|  | ||||
| 	apiClientMeta := &api.PluginAPIClientMeta{} | ||||
| 	flags := apiClientMeta.FlagSet() | ||||
| 	flags.Parse(args) | ||||
|  | ||||
| 	factoryFunc := mock.FactoryType(logical.TypeCredential) | ||||
|  | ||||
| 	err := lplugin.Serve(&lplugin.ServeOpts{ | ||||
| 		BackendFactoryFunc: factoryFunc, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TestBackend_PluginMainEnv is a mock plugin that simply checks for the existence of FOO env var. | ||||
| func TestBackend_PluginMainEnv(t *testing.T) { | ||||
| 	args := []string{} | ||||
| @@ -751,14 +958,11 @@ func TestBackend_PluginMainEnv(t *testing.T) { | ||||
| 	apiClientMeta := &api.PluginAPIClientMeta{} | ||||
| 	flags := apiClientMeta.FlagSet() | ||||
| 	flags.Parse(args) | ||||
| 	tlsConfig := apiClientMeta.GetTLSConfig() | ||||
| 	tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig) | ||||
|  | ||||
| 	factoryFunc := mock.FactoryType(logical.TypeLogical) | ||||
|  | ||||
| 	err := lplugin.Serve(&lplugin.ServeOpts{ | ||||
| 		BackendFactoryFunc: factoryFunc, | ||||
| 		TLSProviderFunc:    tlsProviderFunc, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
|   | ||||
| @@ -325,14 +325,48 @@ func (c *PluginCatalog) getPluginTypeFromUnknown(ctx context.Context, logger log | ||||
| 	} | ||||
| 	merr = multierror.Append(merr, err) | ||||
|  | ||||
| 	// Attempt to run as backend plugin | ||||
| 	client, err := backendplugin.NewPluginClient(ctx, nil, plugin, log.NewNullLogger(), true) | ||||
| 	pluginType, err := c.getBackendPluginType(ctx, plugin) | ||||
| 	if err == nil { | ||||
| 		err := client.Setup(ctx, &logical.BackendConfig{}) | ||||
| 		return pluginType, nil | ||||
| 	} | ||||
| 	merr = multierror.Append(merr, err) | ||||
|  | ||||
| 	return consts.PluginTypeUnknown, merr | ||||
| } | ||||
|  | ||||
| // getBackendPluginType returns the plugin type (secrets/auth) and an error if | ||||
| // the plugin is not a backend plugin. | ||||
| func (c *PluginCatalog) getBackendPluginType(ctx context.Context, pluginRunner *pluginutil.PluginRunner) (consts.PluginType, error) { | ||||
| 	var client logical.Backend | ||||
| 	var merr *multierror.Error | ||||
| 	config := pluginutil.PluginClientConfig{ | ||||
| 		Name:           pluginRunner.Name, | ||||
| 		Logger:         log.NewNullLogger(), | ||||
| 		IsMetadataMode: false, | ||||
| 		AutoMTLS:       true, | ||||
| 	} | ||||
|  | ||||
| 	// Attempt to run as backend V5 plugin | ||||
| 	c.logger.Debug("attempting to load backend plugin", "name", pluginRunner.Name) | ||||
| 	client, err := backendplugin.NewPluginClient(ctx, pluginRunner, config) | ||||
| 	if err != nil { | ||||
| 		merr = multierror.Append(merr, err) | ||||
| 		c.logger.Debug("failed to dispense v5 backend plugin", "name", pluginRunner.Name, "error", err) | ||||
| 		config.AutoMTLS = false | ||||
| 		config.IsMetadataMode = true | ||||
| 		// attemtp to run as a v4 backend plugin | ||||
| 		client, err = backendplugin.NewPluginClient(ctx, pluginRunner, config) | ||||
| 		if err != nil { | ||||
| 			c.logger.Debug("failed to dispense v4 backend plugin", "name", pluginRunner.Name, "error", err) | ||||
| 			return consts.PluginTypeUnknown, merr.ErrorOrNil() | ||||
| 		} | ||||
| 		c.logger.Debug("successfully dispensed v4 backend plugin", "name", pluginRunner.Name) | ||||
| 	} | ||||
|  | ||||
| 	err = client.Setup(ctx, &logical.BackendConfig{}) | ||||
| 	if err != nil { | ||||
| 		return consts.PluginTypeUnknown, err | ||||
| 	} | ||||
|  | ||||
| 	backendType := client.Type() | ||||
| 	client.Cleanup(ctx) | ||||
|  | ||||
| @@ -342,22 +376,21 @@ func (c *PluginCatalog) getPluginTypeFromUnknown(ctx context.Context, logger log | ||||
| 	case logical.TypeLogical: | ||||
| 		return consts.PluginTypeSecrets, nil | ||||
| 	} | ||||
| 	} else { | ||||
| 		merr = multierror.Append(merr, err) | ||||
| 	} | ||||
|  | ||||
| 	if client == nil || client.Type() == logical.TypeUnknown { | ||||
| 		logger.Warn("unknown plugin type", | ||||
| 			"plugin name", plugin.Name, | ||||
| 		c.logger.Warn("unknown plugin type", | ||||
| 			"plugin name", pluginRunner.Name, | ||||
| 			"error", merr.Error()) | ||||
| 	} else { | ||||
| 		logger.Warn("unsupported plugin type", | ||||
| 			"plugin name", plugin.Name, | ||||
| 		c.logger.Warn("unsupported plugin type", | ||||
| 			"plugin name", pluginRunner.Name, | ||||
| 			"plugin type", client.Type().String(), | ||||
| 			"error", merr.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return consts.PluginTypeUnknown, nil | ||||
| 	merr = multierror.Append(merr, fmt.Errorf("failed to load plugin as backend plugin: %w", err)) | ||||
|  | ||||
| 	return consts.PluginTypeUnknown, merr.ErrorOrNil() | ||||
| } | ||||
|  | ||||
| // isDatabasePlugin returns true if the plugin supports multiplexing. An error | ||||
|   | ||||
		Reference in New Issue
	
	Block a user