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 ( | 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 | 	// PluginMetadataModeEnv is an ENV name used to disable TLS communication | ||||||
| 	// to bootstrap mounting plugins. | 	// to bootstrap mounting plugins. | ||||||
| 	PluginMetadataModeEnv = "VAULT_PLUGIN_METADATA_MODE" | 	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 | // VaultPluginTLSProviderContext is run inside a plugin and retrieves the response | ||||||
| // wrapped TLS certificate from vault. It returns a configured TLS Config. | // wrapped TLS certificate from vault. It returns a configured TLS Config. | ||||||
| func VaultPluginTLSProviderContext(ctx context.Context, apiTLSConfig *TLSConfig) func() (*tls.Config, error) { | 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 | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import ( | |||||||
|  |  | ||||||
| 	log "github.com/hashicorp/go-hclog" | 	log "github.com/hashicorp/go-hclog" | ||||||
|  |  | ||||||
|  | 	"github.com/hashicorp/go-multierror" | ||||||
| 	uuid "github.com/hashicorp/go-uuid" | 	uuid "github.com/hashicorp/go-uuid" | ||||||
| 	"github.com/hashicorp/vault/sdk/framework" | 	"github.com/hashicorp/vault/sdk/framework" | ||||||
| 	"github.com/hashicorp/vault/sdk/helper/consts" | 	"github.com/hashicorp/vault/sdk/helper/consts" | ||||||
| @@ -51,17 +52,32 @@ func Backend(ctx context.Context, conf *logical.BackendConfig) (*PluginBackend, | |||||||
|  |  | ||||||
| 	sys := conf.System | 	sys := conf.System | ||||||
|  |  | ||||||
| 	// NewBackend with isMetadataMode set to true | 	merr := &multierror.Error{} | ||||||
| 	raw, err := bplugin.NewBackend(ctx, name, pluginType, sys, conf, true) | 	// NewBackend with isMetadataMode set to false | ||||||
|  | 	raw, err := bplugin.NewBackend(ctx, name, pluginType, sys, conf, false, true) | ||||||
| 	if err != nil { | 	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) | 	err = raw.Setup(ctx, conf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		raw.Cleanup(ctx) | 		raw.Cleanup(ctx) | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	// Get SpecialPaths and BackendType |  | ||||||
| 	paths := raw.SpecialPaths() | 	paths := raw.SpecialPaths() | ||||||
| 	btype := raw.Type() | 	btype := raw.Type() | ||||||
|  |  | ||||||
| @@ -85,7 +101,8 @@ type PluginBackend struct { | |||||||
| 	Backend logical.Backend | 	Backend logical.Backend | ||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
|  |  | ||||||
| 	config *logical.BackendConfig | 	autoMTLSSupported bool | ||||||
|  | 	config            *logical.BackendConfig | ||||||
|  |  | ||||||
| 	// Used to detect if we already reloaded | 	// Used to detect if we already reloaded | ||||||
| 	canary string | 	canary string | ||||||
| @@ -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()) | 	// Ensure proper cleanup of the backend (i.e. call client.Kill()) | ||||||
| 	b.Backend.Cleanup(ctx) | 	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 { | 	if err != nil { | ||||||
| 		return err | 		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 | 	// 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 { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		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 ( | 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 | 	// PluginMlockEnabled is the ENV name used to pass the configuration for | ||||||
| 	// enabling mlock | 	// enabling mlock | ||||||
| 	PluginMlockEnabled = "VAULT_PLUGIN_MLOCK_ENABLED" | 	PluginMlockEnabled = "VAULT_PLUGIN_MLOCK_ENABLED" | ||||||
|   | |||||||
| @@ -9,6 +9,8 @@ import ( | |||||||
| 	status "google.golang.org/grpc/status" | 	status "google.golang.org/grpc/status" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | const MultiplexingCtxKey string = "multiplex_id" | ||||||
|  |  | ||||||
| type PluginMultiplexingServerImpl struct { | type PluginMultiplexingServerImpl struct { | ||||||
| 	UnimplementedPluginMultiplexingServer | 	UnimplementedPluginMultiplexingServer | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ type PluginClientConfig struct { | |||||||
| 	IsMetadataMode  bool | 	IsMetadataMode  bool | ||||||
| 	AutoMTLS        bool | 	AutoMTLS        bool | ||||||
| 	MLock           bool | 	MLock           bool | ||||||
|  | 	Wrapper         RunnerUtil | ||||||
| } | } | ||||||
|  |  | ||||||
| type runConfig struct { | type runConfig struct { | ||||||
| @@ -33,8 +34,6 @@ type runConfig struct { | |||||||
| 	// Initialized with what's in PluginRunner.Env, but can be added to | 	// Initialized with what's in PluginRunner.Env, but can be added to | ||||||
| 	env []string | 	env []string | ||||||
|  |  | ||||||
| 	wrapper RunnerUtil |  | ||||||
|  |  | ||||||
| 	PluginClientConfig | 	PluginClientConfig | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -43,7 +42,7 @@ func (rc runConfig) makeConfig(ctx context.Context) (*plugin.ClientConfig, error | |||||||
| 	cmd.Env = append(cmd.Env, rc.env...) | 	cmd.Env = append(cmd.Env, rc.env...) | ||||||
|  |  | ||||||
| 	// Add the mlock setting to the ENV of the plugin | 	// 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", PluginMlockEnabled, "true")) | ||||||
| 	} | 	} | ||||||
| 	cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version)) | 	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) | 	metadataEnv := fmt.Sprintf("%s=%t", PluginMetadataModeEnv, rc.IsMetadataMode) | ||||||
| 	cmd.Env = append(cmd.Env, metadataEnv) | 	cmd.Env = append(cmd.Env, metadataEnv) | ||||||
|  |  | ||||||
|  | 	automtlsEnv := fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, rc.AutoMTLS) | ||||||
|  | 	cmd.Env = append(cmd.Env, automtlsEnv) | ||||||
|  |  | ||||||
| 	var clientTLSConfig *tls.Config | 	var clientTLSConfig *tls.Config | ||||||
| 	if !rc.AutoMTLS && !rc.IsMetadataMode { | 	if !rc.AutoMTLS && !rc.IsMetadataMode { | ||||||
| 		// Get a CA TLS Certificate | 		// 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 | 		// Use CA to sign a server cert and wrap the values in a response wrapped | ||||||
| 		// token. | 		// token. | ||||||
| 		wrapToken, err := wrapServerConfig(ctx, rc.wrapper, certBytes, key) | 		wrapToken, err := wrapServerConfig(ctx, rc.Wrapper, certBytes, key) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| @@ -120,7 +122,7 @@ func Env(env ...string) RunOpt { | |||||||
|  |  | ||||||
| func Runner(wrapper RunnerUtil) RunOpt { | func Runner(wrapper RunnerUtil) RunOpt { | ||||||
| 	return func(rc *runConfig) { | 	return func(rc *runConfig) { | ||||||
| 		rc.wrapper = wrapper | 		rc.Wrapper = wrapper | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"os/exec" | 	"os/exec" | ||||||
| 	"reflect" |  | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| @@ -14,6 +13,7 @@ import ( | |||||||
| 	"github.com/hashicorp/go-plugin" | 	"github.com/hashicorp/go-plugin" | ||||||
| 	"github.com/hashicorp/vault/sdk/helper/wrapping" | 	"github.com/hashicorp/vault/sdk/helper/wrapping" | ||||||
| 	"github.com/stretchr/testify/mock" | 	"github.com/stretchr/testify/mock" | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestMakeConfig(t *testing.T) { | func TestMakeConfig(t *testing.T) { | ||||||
| @@ -78,6 +78,7 @@ func TestMakeConfig(t *testing.T) { | |||||||
| 						"initial=true", | 						"initial=true", | ||||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), | 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), | ||||||
|  | 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, false), | ||||||
| 					}, | 					}, | ||||||
| 				), | 				), | ||||||
| 				SecureConfig: &plugin.SecureConfig{ | 				SecureConfig: &plugin.SecureConfig{ | ||||||
| @@ -143,6 +144,7 @@ func TestMakeConfig(t *testing.T) { | |||||||
| 						fmt.Sprintf("%s=%t", PluginMlockEnabled, true), | 						fmt.Sprintf("%s=%t", PluginMlockEnabled, true), | ||||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), | 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), | ||||||
|  | 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, false), | ||||||
| 						fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, "testtoken"), | 						fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, "testtoken"), | ||||||
| 					}, | 					}, | ||||||
| 				), | 				), | ||||||
| @@ -205,6 +207,7 @@ func TestMakeConfig(t *testing.T) { | |||||||
| 						"initial=true", | 						"initial=true", | ||||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), | 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), | ||||||
|  | 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, true), | ||||||
| 					}, | 					}, | ||||||
| 				), | 				), | ||||||
| 				SecureConfig: &plugin.SecureConfig{ | 				SecureConfig: &plugin.SecureConfig{ | ||||||
| @@ -266,6 +269,7 @@ func TestMakeConfig(t *testing.T) { | |||||||
| 						"initial=true", | 						"initial=true", | ||||||
| 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | 						fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), | ||||||
| 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), | 						fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), | ||||||
|  | 						fmt.Sprintf("%s=%t", PluginAutoMTLSEnv, true), | ||||||
| 					}, | 					}, | ||||||
| 				), | 				), | ||||||
| 				SecureConfig: &plugin.SecureConfig{ | 				SecureConfig: &plugin.SecureConfig{ | ||||||
| @@ -290,7 +294,7 @@ func TestMakeConfig(t *testing.T) { | |||||||
| 				Return(test.responseWrapInfo, test.responseWrapInfoErr) | 				Return(test.responseWrapInfo, test.responseWrapInfoErr) | ||||||
| 			mockWrapper.On("MlockEnabled"). | 			mockWrapper.On("MlockEnabled"). | ||||||
| 				Return(test.mlockEnabled) | 				Return(test.mlockEnabled) | ||||||
| 			test.rc.wrapper = mockWrapper | 			test.rc.Wrapper = mockWrapper | ||||||
| 			defer mockWrapper.AssertNumberOfCalls(t, "ResponseWrapData", test.responseWrapInfoTimes) | 			defer mockWrapper.AssertNumberOfCalls(t, "ResponseWrapData", test.responseWrapInfoTimes) | ||||||
| 			defer mockWrapper.AssertNumberOfCalls(t, "MlockEnabled", test.mlockEnabledTimes) | 			defer mockWrapper.AssertNumberOfCalls(t, "MlockEnabled", test.mlockEnabledTimes) | ||||||
|  |  | ||||||
| @@ -318,9 +322,7 @@ func TestMakeConfig(t *testing.T) { | |||||||
| 			} | 			} | ||||||
| 			config.TLSConfig = nil | 			config.TLSConfig = nil | ||||||
|  |  | ||||||
| 			if !reflect.DeepEqual(config, test.expectedConfig) { | 			require.Equal(t, config, test.expectedConfig) | ||||||
| 				t.Fatalf("Actual config: %#v\nExpected config: %#v", config, test.expectedConfig) |  | ||||||
| 			} |  | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -38,8 +38,6 @@ type PluginClient interface { | |||||||
| 	plugin.ClientProtocol | 	plugin.ClientProtocol | ||||||
| } | } | ||||||
|  |  | ||||||
| const MultiplexingCtxKey string = "multiplex_id" |  | ||||||
|  |  | ||||||
| // PluginRunner defines the metadata needed to run a plugin securely with | // PluginRunner defines the metadata needed to run a plugin securely with | ||||||
| // go-plugin. | // go-plugin. | ||||||
| type PluginRunner struct { | type PluginRunner struct { | ||||||
|   | |||||||
| @@ -20,9 +20,10 @@ var ( | |||||||
| // GRPCBackendPlugin is the plugin.Plugin implementation that only supports GRPC | // GRPCBackendPlugin is the plugin.Plugin implementation that only supports GRPC | ||||||
| // transport | // transport | ||||||
| type GRPCBackendPlugin struct { | type GRPCBackendPlugin struct { | ||||||
| 	Factory      logical.Factory | 	Factory           logical.Factory | ||||||
| 	MetadataMode bool | 	MetadataMode      bool | ||||||
| 	Logger       log.Logger | 	AutoMTLSSupported bool | ||||||
|  | 	Logger            log.Logger | ||||||
|  |  | ||||||
| 	// Embeding this will disable the netRPC protocol | 	// Embeding this will disable the netRPC protocol | ||||||
| 	plugin.NetRPCUnsupportedPlugin | 	plugin.NetRPCUnsupportedPlugin | ||||||
| @@ -41,12 +42,13 @@ func (b GRPCBackendPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) | |||||||
|  |  | ||||||
| func (b *GRPCBackendPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { | func (b *GRPCBackendPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { | ||||||
| 	ret := &backendGRPCPluginClient{ | 	ret := &backendGRPCPluginClient{ | ||||||
| 		client:       pb.NewBackendClient(c), | 		client:     pb.NewBackendClient(c), | ||||||
| 		clientConn:   c, | 		clientConn: c, | ||||||
| 		broker:       broker, | 		broker:     broker, | ||||||
| 		cleanupCh:    make(chan struct{}), | 		cleanupCh:  make(chan struct{}), | ||||||
| 		doneCtx:      ctx, | 		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 | 	// Create the value and set the type | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
|  |  | ||||||
| 	"github.com/hashicorp/errwrap" | 	"github.com/hashicorp/errwrap" | ||||||
| 	log "github.com/hashicorp/go-hclog" |  | ||||||
| 	plugin "github.com/hashicorp/go-plugin" | 	plugin "github.com/hashicorp/go-plugin" | ||||||
| 	"github.com/hashicorp/vault/sdk/helper/consts" | 	"github.com/hashicorp/vault/sdk/helper/consts" | ||||||
| 	"github.com/hashicorp/vault/sdk/helper/pluginutil" | 	"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. | // 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 backend is returned as a logical.Backend interface. The isMetadataMode param determines whether | ||||||
| // the plugin should run in metadata mode. | // 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 | 	// Look for plugin in the plugin catalog | ||||||
| 	pluginRunner, err := sys.LookupPlugin(ctx, pluginName, pluginType) | 	pluginRunner, err := sys.LookupPlugin(ctx, pluginName, pluginType) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -59,8 +58,16 @@ func NewBackend(ctx context.Context, pluginName string, pluginType consts.Plugin | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
|  | 		config := pluginutil.PluginClientConfig{ | ||||||
|  | 			Name:           pluginName, | ||||||
|  | 			PluginType:     pluginType, | ||||||
|  | 			Logger:         conf.Logger.Named(pluginName), | ||||||
|  | 			IsMetadataMode: isMetadataMode, | ||||||
|  | 			AutoMTLS:       autoMTLS, | ||||||
|  | 			Wrapper:        sys, | ||||||
|  | 		} | ||||||
| 		// create a backendPluginClient instance | 		// create a backendPluginClient instance | ||||||
| 		backend, err = NewPluginClient(ctx, sys, pluginRunner, conf.Logger, isMetadataMode) | 		backend, err = NewPluginClient(ctx, pluginRunner, config) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| @@ -69,34 +76,49 @@ func NewBackend(ctx context.Context, pluginName string, pluginType consts.Plugin | |||||||
| 	return backend, nil | 	return backend, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger, isMetadataMode bool) (logical.Backend, error) { | // pluginSet returns the go-plugin PluginSet that we can dispense. This ensures | ||||||
| 	// pluginMap is the map of plugins we can dispense. | // that plugins that don't support AutoMTLS are run on the appropriate version. | ||||||
| 	pluginSet := map[int]plugin.PluginSet{ | 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 | 		// 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 | 		// since it's possible old plugins built against this version will still | ||||||
| 		// work with gRPC. There is currently no difference between version 3 | 		// work with gRPC. There is currently no difference between version 3 | ||||||
| 		// and version 4. | 		// and version 4. | ||||||
| 		3: { | 		3: { | ||||||
| 			"backend": &GRPCBackendPlugin{ | 			"backend": &GRPCBackendPlugin{ | ||||||
| 				MetadataMode: isMetadataMode, | 				MetadataMode: metadataMode, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		4: { | 		4: { | ||||||
| 			"backend": &GRPCBackendPlugin{ | 			"backend": &GRPCBackendPlugin{ | ||||||
| 				MetadataMode: isMetadataMode, | 				MetadataMode: metadataMode, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| 	namedLogger := logger.Named(pluginRunner.Name) | func NewPluginClient(ctx context.Context, pluginRunner *pluginutil.PluginRunner, config pluginutil.PluginClientConfig) (logical.Backend, error) { | ||||||
|  | 	ps := pluginSet(config.AutoMTLS, config.IsMetadataMode) | ||||||
|  |  | ||||||
| 	var client *plugin.Client | 	client, err := pluginRunner.RunConfig(ctx, | ||||||
| 	var err error | 		pluginutil.Runner(config.Wrapper), | ||||||
| 	if isMetadataMode { | 		pluginutil.PluginSets(ps), | ||||||
| 		client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginSet, handshakeConfig, []string{}, namedLogger) | 		pluginutil.HandshakeConfig(handshakeConfig), | ||||||
| 	} else { | 		pluginutil.Env(), | ||||||
| 		client, err = pluginRunner.Run(ctx, sys, pluginSet, handshakeConfig, []string{}, namedLogger) | 		pluginutil.Logger(config.Logger), | ||||||
| 	} | 		pluginutil.MetadataMode(config.IsMetadataMode), | ||||||
|  | 		pluginutil.AutoMTLS(config.AutoMTLS), | ||||||
|  | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -126,9 +148,9 @@ func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunne | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Wrap the backend in a tracing middleware | 	// Wrap the backend in a tracing middleware | ||||||
| 	if namedLogger.IsTrace() { | 	if config.Logger.IsTrace() { | ||||||
| 		backend = &backendTracingMiddleware{ | 		backend = &backendTracingMiddleware{ | ||||||
| 			logger: namedLogger.With("transport", transport), | 			logger: config.Logger.With("transport", transport), | ||||||
| 			next:   backend, | 			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{ | 	pluginSets := map[int]plugin.PluginSet{ | ||||||
| 		// Version 3 used to supports both protocols. We want to keep it around | 		// 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 | 		// since it's possible old plugins built against this version will still | ||||||
| 		// work with gRPC. There is currently no difference between version 3 | 		// work with gRPC. There is currently no difference between version 3 | ||||||
| 		// and version 4. | 		// and version 4. | ||||||
|  | 		// AutoMTLS is not supported by versions lower than 5. | ||||||
| 		3: { | 		3: { | ||||||
| 			"backend": &GRPCBackendPlugin{ | 			"backend": &GRPCBackendPlugin{ | ||||||
| 				Factory: opts.BackendFactoryFunc, | 				Factory: opts.BackendFactoryFunc, | ||||||
| @@ -55,6 +56,13 @@ func Serve(opts *ServeOpts) error { | |||||||
| 				Logger:  logger, | 				Logger:  logger, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		5: { | ||||||
|  | 			"backend": &GRPCBackendPlugin{ | ||||||
|  | 				Factory:           opts.BackendFactoryFunc, | ||||||
|  | 				Logger:            logger, | ||||||
|  | 				AutoMTLSSupported: true, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err := pluginutil.OptionallyEnableMlock() | 	err := pluginutil.OptionallyEnableMlock() | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -325,39 +325,72 @@ func (c *PluginCatalog) getPluginTypeFromUnknown(ctx context.Context, logger log | |||||||
| 	} | 	} | ||||||
| 	merr = multierror.Append(merr, err) | 	merr = multierror.Append(merr, err) | ||||||
|  |  | ||||||
| 	// Attempt to run as backend plugin | 	pluginType, err := c.getBackendPluginType(ctx, plugin) | ||||||
| 	client, err := backendplugin.NewPluginClient(ctx, nil, plugin, log.NewNullLogger(), true) |  | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		err := client.Setup(ctx, &logical.BackendConfig{}) | 		return pluginType, nil | ||||||
| 		if err != nil { | 	} | ||||||
| 			return consts.PluginTypeUnknown, err | 	merr = multierror.Append(merr, err) | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		backendType := client.Type() | 	return consts.PluginTypeUnknown, merr | ||||||
| 		client.Cleanup(ctx) | } | ||||||
|  |  | ||||||
| 		switch backendType { | // getBackendPluginType returns the plugin type (secrets/auth) and an error if | ||||||
| 		case logical.TypeCredential: | // the plugin is not a backend plugin. | ||||||
| 			return consts.PluginTypeCredential, nil | func (c *PluginCatalog) getBackendPluginType(ctx context.Context, pluginRunner *pluginutil.PluginRunner) (consts.PluginType, error) { | ||||||
| 		case logical.TypeLogical: | 	var client logical.Backend | ||||||
| 			return consts.PluginTypeSecrets, nil | 	var merr *multierror.Error | ||||||
| 		} | 	config := pluginutil.PluginClientConfig{ | ||||||
| 	} else { | 		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) | 		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) | ||||||
|  |  | ||||||
|  | 	switch backendType { | ||||||
|  | 	case logical.TypeCredential: | ||||||
|  | 		return consts.PluginTypeCredential, nil | ||||||
|  | 	case logical.TypeLogical: | ||||||
|  | 		return consts.PluginTypeSecrets, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if client == nil || client.Type() == logical.TypeUnknown { | 	if client == nil || client.Type() == logical.TypeUnknown { | ||||||
| 		logger.Warn("unknown plugin type", | 		c.logger.Warn("unknown plugin type", | ||||||
| 			"plugin name", plugin.Name, | 			"plugin name", pluginRunner.Name, | ||||||
| 			"error", merr.Error()) | 			"error", merr.Error()) | ||||||
| 	} else { | 	} else { | ||||||
| 		logger.Warn("unsupported plugin type", | 		c.logger.Warn("unsupported plugin type", | ||||||
| 			"plugin name", plugin.Name, | 			"plugin name", pluginRunner.Name, | ||||||
| 			"plugin type", client.Type().String(), | 			"plugin type", client.Type().String(), | ||||||
| 			"error", merr.Error()) | 			"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 | // isDatabasePlugin returns true if the plugin supports multiplexing. An error | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user