diff --git a/builtin/logical/database/mockv5.go b/builtin/logical/database/mockv5.go index 320e065703..16f5caa617 100644 --- a/builtin/logical/database/mockv5.go +++ b/builtin/logical/database/mockv5.go @@ -6,7 +6,6 @@ import ( "time" log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/sdk/database/newdbplugin" ) @@ -26,13 +25,13 @@ func New() (interface{}, error) { } // Run instantiates a MongoDB object, and runs the RPC server for the plugin -func RunV5(apiTLSConfig *api.TLSConfig) error { +func RunV5() error { dbType, err := New() if err != nil { return err } - newdbplugin.Serve(dbType.(newdbplugin.Database), api.VaultPluginTLSProvider(apiTLSConfig)) + newdbplugin.Serve(dbType.(newdbplugin.Database)) return nil } diff --git a/builtin/logical/database/versioning_large_test.go b/builtin/logical/database/versioning_large_test.go index 7bbe040850..3e8eff67e3 100644 --- a/builtin/logical/database/versioning_large_test.go +++ b/builtin/logical/database/versioning_large_test.go @@ -265,7 +265,7 @@ func TestBackend_PluginMain_MockV5(t *testing.T) { flags := apiClientMeta.FlagSet() flags.Parse(args) - RunV5(apiClientMeta.GetTLSConfig()) + RunV5() } func assertNoRespData(t *testing.T, resp *logical.Response) { diff --git a/sdk/database/newdbplugin/plugin_client.go b/sdk/database/newdbplugin/plugin_client.go index 812adc2b57..c97c03b735 100644 --- a/sdk/database/newdbplugin/plugin_client.go +++ b/sdk/database/newdbplugin/plugin_client.go @@ -39,13 +39,14 @@ func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunne }, } - var client *plugin.Client - var err error - if isMetadataMode { - client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginSets, handshakeConfig, []string{}, logger) - } else { - client, err = pluginRunner.Run(ctx, sys, pluginSets, handshakeConfig, []string{}, logger) - } + client, err := pluginRunner.RunConfig(ctx, + pluginutil.Runner(sys), + pluginutil.PluginSets(pluginSets), + pluginutil.HandshakeConfig(handshakeConfig), + pluginutil.Logger(logger), + pluginutil.MetadataMode(isMetadataMode), + pluginutil.AutoMTLS(true), + ) if err != nil { return nil, err } diff --git a/sdk/database/newdbplugin/plugin_server.go b/sdk/database/newdbplugin/plugin_server.go index ccb178c874..8098364be6 100644 --- a/sdk/database/newdbplugin/plugin_server.go +++ b/sdk/database/newdbplugin/plugin_server.go @@ -1,7 +1,6 @@ package newdbplugin import ( - "crypto/tls" "fmt" "github.com/hashicorp/go-plugin" @@ -11,11 +10,11 @@ import ( // Serve is called from within a plugin and wraps the provided // Database implementation in a databasePluginRPCServer object and starts a // RPC server. -func Serve(db Database, tlsProvider func() (*tls.Config, error)) { - plugin.Serve(ServeConfig(db, tlsProvider)) +func Serve(db Database) { + plugin.Serve(ServeConfig(db)) } -func ServeConfig(db Database, tlsProvider func() (*tls.Config, error)) *plugin.ServeConfig { +func ServeConfig(db Database) *plugin.ServeConfig { err := pluginutil.OptionallyEnableMlock() if err != nil { fmt.Println(err) @@ -34,7 +33,6 @@ func ServeConfig(db Database, tlsProvider func() (*tls.Config, error)) *plugin.S conf := &plugin.ServeConfig{ HandshakeConfig: handshakeConfig, VersionedPlugins: pluginSets, - TLSProvider: tlsProvider, GRPCServer: plugin.DefaultGRPCServer, } diff --git a/sdk/helper/pluginutil/run_config.go b/sdk/helper/pluginutil/run_config.go new file mode 100644 index 0000000000..f801287d7d --- /dev/null +++ b/sdk/helper/pluginutil/run_config.go @@ -0,0 +1,161 @@ +package pluginutil + +import ( + "context" + "crypto/sha256" + "crypto/tls" + "fmt" + "os/exec" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/sdk/version" +) + +type runConfig struct { + // Provided by PluginRunner + command string + args []string + sha256 []byte + + // Initialized with what's in PluginRunner.Env, but can be added to + env []string + + wrapper RunnerUtil + pluginSets map[int]plugin.PluginSet + hs plugin.HandshakeConfig + logger log.Logger + isMetadataMode bool + autoMTLS bool +} + +func (rc runConfig) makeConfig(ctx context.Context) (*plugin.ClientConfig, error) { + cmd := exec.Command(rc.command, rc.args...) + cmd.Env = append(cmd.Env, rc.env...) + + // Add the mlock setting to the ENV of the plugin + if 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)) + + if rc.isMetadataMode { + rc.logger = rc.logger.With("metadata", "true") + } + metadataEnv := fmt.Sprintf("%s=%t", PluginMetadataModeEnv, rc.isMetadataMode) + cmd.Env = append(cmd.Env, metadataEnv) + + var clientTLSConfig *tls.Config + if !rc.autoMTLS && !rc.isMetadataMode { + // Get a CA TLS Certificate + certBytes, key, err := generateCert() + if err != nil { + return nil, err + } + + // Use CA to sign a client cert and return a configured TLS config + clientTLSConfig, err = createClientTLSConfig(certBytes, key) + if err != nil { + return nil, err + } + + // Use CA to sign a server cert and wrap the values in a response wrapped + // token. + wrapToken, err := wrapServerConfig(ctx, rc.wrapper, certBytes, key) + if err != nil { + return nil, err + } + + // Add the response wrap token to the ENV of the plugin + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, wrapToken)) + } + + secureConfig := &plugin.SecureConfig{ + Checksum: rc.sha256, + Hash: sha256.New(), + } + + clientConfig := &plugin.ClientConfig{ + HandshakeConfig: rc.hs, + VersionedPlugins: rc.pluginSets, + Cmd: cmd, + SecureConfig: secureConfig, + TLSConfig: clientTLSConfig, + Logger: rc.logger, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + AutoMTLS: rc.autoMTLS, + } + return clientConfig, nil +} + +func (rc runConfig) run(ctx context.Context) (*plugin.Client, error) { + clientConfig, err := rc.makeConfig(ctx) + if err != nil { + return nil, err + } + + client := plugin.NewClient(clientConfig) + return client, nil +} + +type RunOpt func(*runConfig) + +func Env(env ...string) RunOpt { + return func(rc *runConfig) { + rc.env = append(rc.env, env...) + } +} + +func Runner(wrapper RunnerUtil) RunOpt { + return func(rc *runConfig) { + rc.wrapper = wrapper + } +} + +func PluginSets(pluginSets map[int]plugin.PluginSet) RunOpt { + return func(rc *runConfig) { + rc.pluginSets = pluginSets + } +} + +func HandshakeConfig(hs plugin.HandshakeConfig) RunOpt { + return func(rc *runConfig) { + rc.hs = hs + } +} + +func Logger(logger log.Logger) RunOpt { + return func(rc *runConfig) { + rc.logger = logger + } +} + +func MetadataMode(isMetadataMode bool) RunOpt { + return func(rc *runConfig) { + rc.isMetadataMode = isMetadataMode + } +} + +func AutoMTLS(autoMTLS bool) RunOpt { + return func(rc *runConfig) { + rc.autoMTLS = autoMTLS + } +} + +func (r *PluginRunner) RunConfig(ctx context.Context, opts ...RunOpt) (*plugin.Client, error) { + rc := runConfig{ + command: r.Command, + args: r.Args, + sha256: r.Sha256, + env: r.Env, + } + + for _, opt := range opts { + opt(&rc) + } + + return rc.run(ctx) +} diff --git a/sdk/helper/pluginutil/run_config_test.go b/sdk/helper/pluginutil/run_config_test.go new file mode 100644 index 0000000000..4a69ef3176 --- /dev/null +++ b/sdk/helper/pluginutil/run_config_test.go @@ -0,0 +1,341 @@ +package pluginutil + +import ( + "context" + "fmt" + "os/exec" + "reflect" + "testing" + "time" + + "github.com/hashicorp/vault/sdk/version" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/sdk/helper/wrapping" + "github.com/stretchr/testify/mock" +) + +func TestNameMakeConfig(t *testing.T) { + type testCase struct { + rc runConfig + + responseWrapInfo *wrapping.ResponseWrapInfo + responseWrapInfoErr error + responseWrapInfoTimes int + + mlockEnabled bool + mlockEnabledTimes int + + expectedConfig *plugin.ClientConfig + expectTLSConfig bool + } + + tests := map[string]testCase{ + "metadata mode, not-AutoMTLS": { + rc: runConfig{ + command: "echo", + args: []string{"foo", "bar"}, + sha256: []byte("some_sha256"), + env: []string{"initial=true"}, + pluginSets: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + hs: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + logger: hclog.NewNullLogger(), + isMetadataMode: true, + autoMTLS: false, + }, + + responseWrapInfoTimes: 0, + + mlockEnabled: false, + mlockEnabledTimes: 1, + + expectedConfig: &plugin.ClientConfig{ + HandshakeConfig: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + VersionedPlugins: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + Cmd: commandWithEnv( + "echo", + []string{"foo", "bar"}, + []string{ + "initial=true", + fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), + fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), + }, + ), + SecureConfig: &plugin.SecureConfig{ + Checksum: []byte("some_sha256"), + // Hash is generated + }, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + Logger: hclog.NewNullLogger(), + AutoMTLS: false, + }, + expectTLSConfig: false, + }, + "non-metadata mode, not-AutoMTLS": { + rc: runConfig{ + command: "echo", + args: []string{"foo", "bar"}, + sha256: []byte("some_sha256"), + env: []string{"initial=true"}, + pluginSets: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + hs: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + logger: hclog.NewNullLogger(), + isMetadataMode: false, + autoMTLS: false, + }, + + responseWrapInfo: &wrapping.ResponseWrapInfo{ + Token: "testtoken", + }, + responseWrapInfoTimes: 1, + + mlockEnabled: true, + mlockEnabledTimes: 1, + + expectedConfig: &plugin.ClientConfig{ + HandshakeConfig: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + VersionedPlugins: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + Cmd: commandWithEnv( + "echo", + []string{"foo", "bar"}, + []string{ + "initial=true", + fmt.Sprintf("%s=%t", PluginMlockEnabled, true), + fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), + fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), + fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, "testtoken"), + }, + ), + SecureConfig: &plugin.SecureConfig{ + Checksum: []byte("some_sha256"), + // Hash is generated + }, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + Logger: hclog.NewNullLogger(), + AutoMTLS: false, + }, + expectTLSConfig: true, + }, + "metadata mode, AutoMTLS": { + rc: runConfig{ + command: "echo", + args: []string{"foo", "bar"}, + sha256: []byte("some_sha256"), + env: []string{"initial=true"}, + pluginSets: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + hs: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + logger: hclog.NewNullLogger(), + isMetadataMode: true, + autoMTLS: true, + }, + + responseWrapInfoTimes: 0, + + mlockEnabled: false, + mlockEnabledTimes: 1, + + expectedConfig: &plugin.ClientConfig{ + HandshakeConfig: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + VersionedPlugins: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + Cmd: commandWithEnv( + "echo", + []string{"foo", "bar"}, + []string{ + "initial=true", + fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), + fmt.Sprintf("%s=%t", PluginMetadataModeEnv, true), + }, + ), + SecureConfig: &plugin.SecureConfig{ + Checksum: []byte("some_sha256"), + // Hash is generated + }, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + Logger: hclog.NewNullLogger(), + AutoMTLS: true, + }, + expectTLSConfig: false, + }, + "not-metadata mode, AutoMTLS": { + rc: runConfig{ + command: "echo", + args: []string{"foo", "bar"}, + sha256: []byte("some_sha256"), + env: []string{"initial=true"}, + pluginSets: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + hs: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + logger: hclog.NewNullLogger(), + isMetadataMode: false, + autoMTLS: true, + }, + + responseWrapInfoTimes: 0, + + mlockEnabled: false, + mlockEnabledTimes: 1, + + expectedConfig: &plugin.ClientConfig{ + HandshakeConfig: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "magic_cookie_key", + MagicCookieValue: "magic_cookie_value", + }, + VersionedPlugins: map[int]plugin.PluginSet{ + 1: plugin.PluginSet{ + "bogus": nil, + }, + }, + Cmd: commandWithEnv( + "echo", + []string{"foo", "bar"}, + []string{ + "initial=true", + fmt.Sprintf("%s=%s", PluginVaultVersionEnv, version.GetVersion().Version), + fmt.Sprintf("%s=%t", PluginMetadataModeEnv, false), + }, + ), + SecureConfig: &plugin.SecureConfig{ + Checksum: []byte("some_sha256"), + // Hash is generated + }, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + Logger: hclog.NewNullLogger(), + AutoMTLS: true, + }, + expectTLSConfig: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + mockWrapper := new(mockRunnerUtil) + mockWrapper.On("ResponseWrapData", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(test.responseWrapInfo, test.responseWrapInfoErr) + mockWrapper.On("MlockEnabled"). + Return(test.mlockEnabled) + test.rc.wrapper = mockWrapper + defer mockWrapper.AssertNumberOfCalls(t, "ResponseWrapData", test.responseWrapInfoTimes) + defer mockWrapper.AssertNumberOfCalls(t, "MlockEnabled", test.mlockEnabledTimes) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + config, err := test.rc.makeConfig(ctx) + if err != nil { + t.Fatalf("no error expected, got: %s", err) + } + + // TODO: Certain fields will need to be checked for existence, not specific value + // The following fields are generated, so we just need to check for existence, not specific value + // The value must be nilled out before performing a DeepEqual check + hsh := config.SecureConfig.Hash + if hsh == nil { + t.Fatalf("Missing SecureConfig.Hash") + } + config.SecureConfig.Hash = nil + + if test.expectTLSConfig && config.TLSConfig == nil { + t.Fatalf("TLS config expected, got nil") + } + if !test.expectTLSConfig && config.TLSConfig != nil { + t.Fatalf("no TLS config expected, got: %#v", config.TLSConfig) + } + config.TLSConfig = nil + + if !reflect.DeepEqual(config, test.expectedConfig) { + t.Fatalf("Actual config: %#v\nExpected config: %#v", config, test.expectedConfig) + } + }) + } +} + +func commandWithEnv(cmd string, args []string, env []string) *exec.Cmd { + c := exec.Command(cmd, args...) + c.Env = env + return c +} + +var _ RunnerUtil = &mockRunnerUtil{} + +type mockRunnerUtil struct { + mock.Mock +} + +func (m *mockRunnerUtil) ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) { + args := m.Called(ctx, data, ttl, jwt) + return args.Get(0).(*wrapping.ResponseWrapInfo), args.Error(1) +} + +func (m *mockRunnerUtil) MlockEnabled() bool { + args := m.Called() + return args.Bool(0) +} diff --git a/sdk/helper/pluginutil/runner.go b/sdk/helper/pluginutil/runner.go index a572363020..ecd60eeb34 100644 --- a/sdk/helper/pluginutil/runner.go +++ b/sdk/helper/pluginutil/runner.go @@ -2,17 +2,12 @@ package pluginutil import ( "context" - "crypto/sha256" - "crypto/tls" - "fmt" - "os/exec" "time" 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/wrapping" - "github.com/hashicorp/vault/sdk/version" ) // Looker defines the plugin Lookup function that looks into the plugin catalog @@ -53,83 +48,28 @@ type PluginRunner struct { // returns a configured plugin.Client with TLS Configured and a wrapping token set // on PluginUnwrapTokenEnv for plugin process consumption. func (r *PluginRunner) Run(ctx context.Context, wrapper RunnerUtil, pluginSets map[int]plugin.PluginSet, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) { - return r.runCommon(ctx, wrapper, pluginSets, hs, env, logger, false) + return r.RunConfig(ctx, + Runner(wrapper), + PluginSets(pluginSets), + HandshakeConfig(hs), + Env(env...), + Logger(logger), + MetadataMode(false), + ) } // RunMetadataMode returns a configured plugin.Client that will dispense a plugin // in metadata mode. The PluginMetadataModeEnv is passed in as part of the Cmd to // plugin.Client, and consumed by the plugin process on api.VaultPluginTLSProvider. func (r *PluginRunner) RunMetadataMode(ctx context.Context, wrapper RunnerUtil, pluginSets map[int]plugin.PluginSet, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) { - return r.runCommon(ctx, wrapper, pluginSets, hs, env, logger, true) - -} - -func (r *PluginRunner) runCommon(ctx context.Context, wrapper RunnerUtil, pluginSets map[int]plugin.PluginSet, hs plugin.HandshakeConfig, env []string, logger log.Logger, isMetadataMode bool) (*plugin.Client, error) { - cmd := exec.Command(r.Command, r.Args...) - - // `env` should always go last to avoid overwriting internal values that might - // have been provided externally. - cmd.Env = append(cmd.Env, r.Env...) - cmd.Env = append(cmd.Env, env...) - - // Add the mlock setting to the ENV of the plugin - if wrapper != nil && 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)) - - var clientTLSConfig *tls.Config - if !isMetadataMode { - // Add the metadata mode ENV and set it to false - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "false")) - - // Get a CA TLS Certificate - certBytes, key, err := generateCert() - if err != nil { - return nil, err - } - - // Use CA to sign a client cert and return a configured TLS config - clientTLSConfig, err = createClientTLSConfig(certBytes, key) - if err != nil { - return nil, err - } - - // Use CA to sign a server cert and wrap the values in a response wrapped - // token. - wrapToken, err := wrapServerConfig(ctx, wrapper, certBytes, key) - if err != nil { - return nil, err - } - - // Add the response wrap token to the ENV of the plugin - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, wrapToken)) - } else { - logger = logger.With("metadata", "true") - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "true")) - } - - secureConfig := &plugin.SecureConfig{ - Checksum: r.Sha256, - Hash: sha256.New(), - } - - clientConfig := &plugin.ClientConfig{ - HandshakeConfig: hs, - VersionedPlugins: pluginSets, - Cmd: cmd, - SecureConfig: secureConfig, - TLSConfig: clientTLSConfig, - Logger: logger, - AllowedProtocols: []plugin.Protocol{ - plugin.ProtocolNetRPC, - plugin.ProtocolGRPC, - }, - } - - client := plugin.NewClient(clientConfig) - - return client, nil + return r.RunConfig(ctx, + Runner(wrapper), + PluginSets(pluginSets), + HandshakeConfig(hs), + Env(env...), + Logger(logger), + MetadataMode(true), + ) } // CtxCancelIfCanceled takes a context cancel func and a context. If the context is diff --git a/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_client.go b/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_client.go index 812adc2b57..c97c03b735 100644 --- a/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_client.go +++ b/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_client.go @@ -39,13 +39,14 @@ func NewPluginClient(ctx context.Context, sys pluginutil.RunnerUtil, pluginRunne }, } - var client *plugin.Client - var err error - if isMetadataMode { - client, err = pluginRunner.RunMetadataMode(ctx, sys, pluginSets, handshakeConfig, []string{}, logger) - } else { - client, err = pluginRunner.Run(ctx, sys, pluginSets, handshakeConfig, []string{}, logger) - } + client, err := pluginRunner.RunConfig(ctx, + pluginutil.Runner(sys), + pluginutil.PluginSets(pluginSets), + pluginutil.HandshakeConfig(handshakeConfig), + pluginutil.Logger(logger), + pluginutil.MetadataMode(isMetadataMode), + pluginutil.AutoMTLS(true), + ) if err != nil { return nil, err } diff --git a/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_server.go b/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_server.go index ccb178c874..8098364be6 100644 --- a/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_server.go +++ b/vendor/github.com/hashicorp/vault/sdk/database/newdbplugin/plugin_server.go @@ -1,7 +1,6 @@ package newdbplugin import ( - "crypto/tls" "fmt" "github.com/hashicorp/go-plugin" @@ -11,11 +10,11 @@ import ( // Serve is called from within a plugin and wraps the provided // Database implementation in a databasePluginRPCServer object and starts a // RPC server. -func Serve(db Database, tlsProvider func() (*tls.Config, error)) { - plugin.Serve(ServeConfig(db, tlsProvider)) +func Serve(db Database) { + plugin.Serve(ServeConfig(db)) } -func ServeConfig(db Database, tlsProvider func() (*tls.Config, error)) *plugin.ServeConfig { +func ServeConfig(db Database) *plugin.ServeConfig { err := pluginutil.OptionallyEnableMlock() if err != nil { fmt.Println(err) @@ -34,7 +33,6 @@ func ServeConfig(db Database, tlsProvider func() (*tls.Config, error)) *plugin.S conf := &plugin.ServeConfig{ HandshakeConfig: handshakeConfig, VersionedPlugins: pluginSets, - TLSProvider: tlsProvider, GRPCServer: plugin.DefaultGRPCServer, } diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/run_config.go b/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/run_config.go new file mode 100644 index 0000000000..105214a6f8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/run_config.go @@ -0,0 +1,154 @@ +package pluginutil + +import ( + "context" + "crypto/sha256" + "crypto/tls" + "fmt" + "os/exec" + + log "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/vault/sdk/version" +) + +type runConfig struct { + // Provided by PluginRunner + command string + args []string + sha256 []byte + + // Initialized with what's in PluginRunner.Env, but can be added to + env []string + + wrapper RunnerUtil + pluginSets map[int]plugin.PluginSet + hs plugin.HandshakeConfig + logger log.Logger + isMetadataMode bool + autoMTLS bool +} + +func (rc runConfig) run(ctx context.Context) (*plugin.Client, error) { + cmd := exec.Command(rc.command, rc.args...) + cmd.Env = append(cmd.Env, rc.env...) + + // Add the mlock setting to the ENV of the plugin + if 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)) + + var clientTLSConfig *tls.Config + if !rc.isMetadataMode { + // Add the metadata mode ENV and set it to false + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "false")) + + // Get a CA TLS Certificate + certBytes, key, err := generateCert() + if err != nil { + return nil, err + } + + // Use CA to sign a client cert and return a configured TLS config + clientTLSConfig, err = createClientTLSConfig(certBytes, key) + if err != nil { + return nil, err + } + + // Use CA to sign a server cert and wrap the values in a response wrapped + // token. + wrapToken, err := wrapServerConfig(ctx, rc.wrapper, certBytes, key) + if err != nil { + return nil, err + } + + // Add the response wrap token to the ENV of the plugin + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, wrapToken)) + } else { + rc.logger = rc.logger.With("metadata", "true") + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "true")) + } + + secureConfig := &plugin.SecureConfig{ + Checksum: rc.sha256, + Hash: sha256.New(), + } + + clientConfig := &plugin.ClientConfig{ + HandshakeConfig: rc.hs, + VersionedPlugins: rc.pluginSets, + Cmd: cmd, + SecureConfig: secureConfig, + TLSConfig: clientTLSConfig, + Logger: rc.logger, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolNetRPC, + plugin.ProtocolGRPC, + }, + AutoMTLS: rc.autoMTLS, + } + + client := plugin.NewClient(clientConfig) + + return client, nil +} + +type RunOpt func(*runConfig) + +func Env(env ...string) RunOpt { + return func(rc *runConfig) { + rc.env = append(rc.env, env...) + } +} + +func Runner(wrapper RunnerUtil) RunOpt { + return func(rc *runConfig) { + rc.wrapper = wrapper + } +} + +func PluginSets(pluginSets map[int]plugin.PluginSet) RunOpt { + return func(rc *runConfig) { + rc.pluginSets = pluginSets + } +} + +func HandshakeConfig(hs plugin.HandshakeConfig) RunOpt { + return func(rc *runConfig) { + rc.hs = hs + } +} + +func Logger(logger log.Logger) RunOpt { + return func(rc *runConfig) { + rc.logger = logger + } +} + +func MetadataMode(isMetadataMode bool) RunOpt { + return func(rc *runConfig) { + rc.isMetadataMode = isMetadataMode + } +} + +func AutoMTLS(autoMTLS bool) RunOpt { + return func(rc *runConfig) { + rc.autoMTLS = autoMTLS + } +} + +func (r *PluginRunner) RunConfig(ctx context.Context, opts ...RunOpt) (*plugin.Client, error) { + rc := runConfig{ + command: r.Command, + args: r.Args, + sha256: r.Sha256, + env: r.Env, + } + + for _, opt := range opts { + opt(&rc) + } + + return rc.run(ctx) +} diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/runner.go b/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/runner.go index a572363020..ecd60eeb34 100644 --- a/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/runner.go +++ b/vendor/github.com/hashicorp/vault/sdk/helper/pluginutil/runner.go @@ -2,17 +2,12 @@ package pluginutil import ( "context" - "crypto/sha256" - "crypto/tls" - "fmt" - "os/exec" "time" 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/wrapping" - "github.com/hashicorp/vault/sdk/version" ) // Looker defines the plugin Lookup function that looks into the plugin catalog @@ -53,83 +48,28 @@ type PluginRunner struct { // returns a configured plugin.Client with TLS Configured and a wrapping token set // on PluginUnwrapTokenEnv for plugin process consumption. func (r *PluginRunner) Run(ctx context.Context, wrapper RunnerUtil, pluginSets map[int]plugin.PluginSet, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) { - return r.runCommon(ctx, wrapper, pluginSets, hs, env, logger, false) + return r.RunConfig(ctx, + Runner(wrapper), + PluginSets(pluginSets), + HandshakeConfig(hs), + Env(env...), + Logger(logger), + MetadataMode(false), + ) } // RunMetadataMode returns a configured plugin.Client that will dispense a plugin // in metadata mode. The PluginMetadataModeEnv is passed in as part of the Cmd to // plugin.Client, and consumed by the plugin process on api.VaultPluginTLSProvider. func (r *PluginRunner) RunMetadataMode(ctx context.Context, wrapper RunnerUtil, pluginSets map[int]plugin.PluginSet, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) { - return r.runCommon(ctx, wrapper, pluginSets, hs, env, logger, true) - -} - -func (r *PluginRunner) runCommon(ctx context.Context, wrapper RunnerUtil, pluginSets map[int]plugin.PluginSet, hs plugin.HandshakeConfig, env []string, logger log.Logger, isMetadataMode bool) (*plugin.Client, error) { - cmd := exec.Command(r.Command, r.Args...) - - // `env` should always go last to avoid overwriting internal values that might - // have been provided externally. - cmd.Env = append(cmd.Env, r.Env...) - cmd.Env = append(cmd.Env, env...) - - // Add the mlock setting to the ENV of the plugin - if wrapper != nil && 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)) - - var clientTLSConfig *tls.Config - if !isMetadataMode { - // Add the metadata mode ENV and set it to false - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "false")) - - // Get a CA TLS Certificate - certBytes, key, err := generateCert() - if err != nil { - return nil, err - } - - // Use CA to sign a client cert and return a configured TLS config - clientTLSConfig, err = createClientTLSConfig(certBytes, key) - if err != nil { - return nil, err - } - - // Use CA to sign a server cert and wrap the values in a response wrapped - // token. - wrapToken, err := wrapServerConfig(ctx, wrapper, certBytes, key) - if err != nil { - return nil, err - } - - // Add the response wrap token to the ENV of the plugin - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginUnwrapTokenEnv, wrapToken)) - } else { - logger = logger.With("metadata", "true") - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", PluginMetadataModeEnv, "true")) - } - - secureConfig := &plugin.SecureConfig{ - Checksum: r.Sha256, - Hash: sha256.New(), - } - - clientConfig := &plugin.ClientConfig{ - HandshakeConfig: hs, - VersionedPlugins: pluginSets, - Cmd: cmd, - SecureConfig: secureConfig, - TLSConfig: clientTLSConfig, - Logger: logger, - AllowedProtocols: []plugin.Protocol{ - plugin.ProtocolNetRPC, - plugin.ProtocolGRPC, - }, - } - - client := plugin.NewClient(clientConfig) - - return client, nil + return r.RunConfig(ctx, + Runner(wrapper), + PluginSets(pluginSets), + HandshakeConfig(hs), + Env(env...), + Logger(logger), + MetadataMode(true), + ) } // CtxCancelIfCanceled takes a context cancel func and a context. If the context is diff --git a/vendor/github.com/kr/pretty/formatter.go b/vendor/github.com/kr/pretty/formatter.go index df61d8d19e..bf4b598d06 100644 --- a/vendor/github.com/kr/pretty/formatter.go +++ b/vendor/github.com/kr/pretty/formatter.go @@ -37,7 +37,7 @@ func (fo formatter) passThrough(f fmt.State, c rune) { s := "%" for i := 0; i < 128; i++ { if f.Flag(i) { - s += string(i) + s += string(rune(i)) } } if w, ok := f.Width(); ok { diff --git a/vendor/modules.txt b/vendor/modules.txt index 47fedce5f7..6ff922af8e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -657,7 +657,7 @@ github.com/keybase/go-crypto/openpgp/s2k github.com/keybase/go-crypto/rsa # github.com/konsorten/go-windows-terminal-sequences v1.0.3 github.com/konsorten/go-windows-terminal-sequences -# github.com/kr/pretty v0.2.0 +# github.com/kr/pretty v0.2.1 github.com/kr/pretty # github.com/kr/text v0.2.0 github.com/kr/text