diff --git a/api/go.mod b/api/go.mod index 29810c6ca9..087b8a6ffd 100644 --- a/api/go.mod +++ b/api/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.6.2 github.com/hashicorp/go-rootcerts v1.0.1 github.com/hashicorp/hcl v1.0.0 - github.com/hashicorp/vault/sdk v0.1.14-0.20200215195600-2ca765f0a500 + github.com/hashicorp/vault/sdk v0.1.14-0.20200310200459-8f075a2701b4 github.com/mitchellh/mapstructure v1.1.2 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 diff --git a/builtin/credential/okta/path_config.go b/builtin/credential/okta/path_config.go index 7faede370a..538d4b537f 100644 --- a/builtin/credential/okta/path_config.go +++ b/builtin/credential/okta/path_config.go @@ -3,12 +3,12 @@ package okta import ( "context" "fmt" - "github.com/hashicorp/go-cleanhttp" "net/http" "net/url" "strings" "time" + "github.com/hashicorp/go-cleanhttp" oktaold "github.com/chrismalek/oktasdk-go/okta" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/tokenutil" diff --git a/builtin/logical/database/rollback_test.go b/builtin/logical/database/rollback_test.go index 9ce06d2d07..36ce2ea596 100644 --- a/builtin/logical/database/rollback_test.go +++ b/builtin/logical/database/rollback_test.go @@ -2,12 +2,13 @@ package database import ( "context" + "strings" + "testing" + "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/database/dbplugin" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" - "strings" - "testing" ) const ( diff --git a/command/agent.go b/command/agent.go index 18f89ced77..793f26a316 100644 --- a/command/agent.go +++ b/command/agent.go @@ -482,15 +482,8 @@ func (c *AgentCommand) Run(args []string) int { // Parse 'require_request_header' listener config option, and wrap // the request handler if necessary muxHandler := cacheHandler - if v, ok := lnConfig.Config[agentConfig.RequireRequestHeader]; ok { - switch v { - case true: - muxHandler = verifyRequestHeader(muxHandler) - case false /* noop */ : - default: - c.UI.Error(fmt.Sprintf("Invalid value for 'require_request_header': %v", v)) - return 1 - } + if lnConfig.RequireRequestHeader { + muxHandler = verifyRequestHeader(muxHandler) } // Create a muxer and add paths relevant for the lease cache layer diff --git a/command/agent/cache/listener.go b/command/agent/cache/listener.go index 508b3d292b..4febcd83ce 100644 --- a/command/agent/cache/listener.go +++ b/command/agent/cache/listener.go @@ -7,16 +7,13 @@ import ( "strings" - "github.com/hashicorp/vault/command/agent/config" "github.com/hashicorp/vault/command/server" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/internalshared/listenerutil" ) -func StartListener(lnConfig *config.Listener) (net.Listener, *tls.Config, error) { - addr, ok := lnConfig.Config["address"].(string) - if !ok { - return nil, nil, fmt.Errorf("invalid address") - } +func StartListener(lnConfig *configutil.Listener) (net.Listener, *tls.Config, error) { + addr := lnConfig.Address var ln net.Listener var err error @@ -41,13 +38,13 @@ func StartListener(lnConfig *config.Listener) (net.Listener, *tls.Config, error) case "unix": var uConfig *listenerutil.UnixSocketsConfig - if lnConfig.Config["socket_mode"] != nil && - lnConfig.Config["socket_user"] != nil && - lnConfig.Config["socket_group"] != nil { + if lnConfig.SocketMode != "" && + lnConfig.SocketUser != "" && + lnConfig.SocketGroup != "" { uConfig = &listenerutil.UnixSocketsConfig{ - Mode: lnConfig.Config["socket_mode"].(string), - User: lnConfig.Config["socket_user"].(string), - Group: lnConfig.Config["socket_group"].(string), + Mode: lnConfig.SocketMode, + User: lnConfig.SocketUser, + Group: lnConfig.SocketGroup, } } ln, err = listenerutil.UnixSocketListener(addr, uConfig) @@ -60,10 +57,13 @@ func StartListener(lnConfig *config.Listener) (net.Listener, *tls.Config, error) } props := map[string]string{"addr": ln.Addr().String()} - ln, props, _, tlsConf, err := listenerutil.WrapTLS(ln, props, lnConfig.Config, nil) + tlsConf, _, err := listenerutil.TLSConfig(lnConfig, props, nil) if err != nil { return nil, nil, err } + if tlsConf != nil { + ln = tls.NewListener(ln, tlsConf) + } return ln, tlsConf, nil } diff --git a/command/agent/cache/testing.go b/command/agent/cache/testing.go index c6113590d3..ca5e526e4a 100644 --- a/command/agent/cache/testing.go +++ b/command/agent/cache/testing.go @@ -72,11 +72,11 @@ type mockTokenVerifierProxier struct { func (p *mockTokenVerifierProxier) Send(ctx context.Context, req *SendRequest) (*SendResponse, error) { p.currentToken = req.Token resp := newTestSendResponse(http.StatusOK, - `{"data": {"id": "` + p.currentToken + `"}}`) + `{"data": {"id": "`+p.currentToken+`"}}`) return resp, nil } -func (p *mockTokenVerifierProxier) GetCurrentRequestToken() (string) { +func (p *mockTokenVerifierProxier) GetCurrentRequestToken() string { return p.currentToken -} \ No newline at end of file +} diff --git a/command/agent/config/config.go b/command/agent/config/config.go index e84ba3b62c..f29cc92acf 100644 --- a/command/agent/config/config.go +++ b/command/agent/config/config.go @@ -14,16 +14,17 @@ import ( "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/parseutil" "github.com/mitchellh/mapstructure" ) // Config is the configuration for the vault server. type Config struct { + *configutil.SharedConfig `hcl:"-"` + AutoAuth *AutoAuth `hcl:"auto_auth"` ExitAfterAuth bool `hcl:"exit_after_auth"` - PidFile string `hcl:"pid_file"` - Listeners []*Listener `hcl:"listeners"` Cache *Cache `hcl:"cache"` Vault *Vault `hcl:"vault"` Templates []*ctconfig.TemplateConfig `hcl:"templates"` @@ -48,15 +49,6 @@ type Cache struct { ForceAutoAuthToken bool `hcl:"-"` } -// Listener contains configuration for any Vault Agent listeners -type Listener struct { - Type string - Config map[string]interface{} -} - -// RequireRequestHeader is a listener configuration option -const RequireRequestHeader = "require_request_header" - // AutoAuth is the configured authentication method and sinks type AutoAuth struct { Method *Method `hcl:"-"` @@ -89,6 +81,12 @@ type Sink struct { Config map[string]interface{} } +func NewConfig() *Config { + return &Config{ + SharedConfig: new(configutil.SharedConfig), + } +} + // LoadConfig loads the configuration at the given path, regardless if // its a file or directory. func LoadConfig(path string) (*Config, error) { @@ -114,29 +112,31 @@ func LoadConfig(path string) (*Config, error) { } // Start building the result - var result Config - if err := hcl.DecodeObject(&result, obj); err != nil { + result := NewConfig() + if err := hcl.DecodeObject(result, obj); err != nil { return nil, err } + sharedConfig, err := configutil.ParseConfig(string(d)) + if err != nil { + return nil, err + } + result.SharedConfig = sharedConfig + list, ok := obj.Node.(*ast.ObjectList) if !ok { return nil, fmt.Errorf("error parsing: file doesn't contain a root object") } - if err := parseAutoAuth(&result, list); err != nil { + if err := parseAutoAuth(result, list); err != nil { return nil, errwrap.Wrapf("error parsing 'auto_auth': {{err}}", err) } - if err := parseListeners(&result, list); err != nil { - return nil, errwrap.Wrapf("error parsing 'listeners': {{err}}", err) - } - - if err := parseCache(&result, list); err != nil { + if err := parseCache(result, list); err != nil { return nil, errwrap.Wrapf("error parsing 'cache':{{err}}", err) } - if err := parseTemplates(&result, list); err != nil { + if err := parseTemplates(result, list); err != nil { return nil, errwrap.Wrapf("error parsing 'template': {{err}}", err) } @@ -161,12 +161,12 @@ func LoadConfig(path string) (*Config, error) { } } - err = parseVault(&result, list) + err = parseVault(result, list) if err != nil { return nil, errwrap.Wrapf("error parsing 'vault':{{err}}", err) } - return &result, nil + return result, nil } func parseVault(result *Config, list *ast.ObjectList) error { @@ -245,47 +245,6 @@ func parseCache(result *Config, list *ast.ObjectList) error { return nil } -func parseListeners(result *Config, list *ast.ObjectList) error { - name := "listener" - - listenerList := list.Filter(name) - - var listeners []*Listener - for _, item := range listenerList.Items { - var lnConfig map[string]interface{} - err := hcl.DecodeObject(&lnConfig, item.Val) - if err != nil { - return err - } - - var lnType string - switch { - case lnConfig["type"] != nil: - lnType = lnConfig["type"].(string) - delete(lnConfig, "type") - case len(item.Keys) == 1: - lnType = strings.ToLower(item.Keys[0].Token.Value().(string)) - default: - return errors.New("listener type must be specified") - } - - switch lnType { - case "unix", "tcp": - default: - return fmt.Errorf("invalid listener type %q", lnType) - } - - listeners = append(listeners, &Listener{ - Type: lnType, - Config: lnConfig, - }) - } - - result.Listeners = listeners - - return nil -} - func parseAutoAuth(result *Config, list *ast.ObjectList) error { name := "auto_auth" diff --git a/command/agent/config/config_test.go b/command/agent/config/config_test.go index d5df544a25..b5e24e5eee 100644 --- a/command/agent/config/config_test.go +++ b/command/agent/config/config_test.go @@ -7,6 +7,7 @@ import ( "github.com/go-test/deep" ctconfig "github.com/hashicorp/consul-template/config" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/pointerutil" ) @@ -17,6 +18,30 @@ func TestLoadConfigFile_AgentCache(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + PidFile: "./pidfile", + Listeners: []*configutil.Listener{ + { + Type: "unix", + Address: "/path/to/socket", + TLSDisable: true, + SocketMode: "configmode", + SocketUser: "configuser", + SocketGroup: "configgroup", + }, + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + { + Type: "tcp", + Address: "127.0.0.1:8400", + TLSKeyFile: "/path/to/cakey.pem", + TLSCertFile: "/path/to/cacert.pem", + }, + }, + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -26,7 +51,7 @@ func TestLoadConfigFile_AgentCache(t *testing.T) { }, }, Sinks: []*Sink{ - &Sink{ + { Type: "file", DHType: "curve25519", DHPath: "/tmp/file-foo-dhpath", @@ -42,33 +67,6 @@ func TestLoadConfigFile_AgentCache(t *testing.T) { UseAutoAuthTokenRaw: true, ForceAutoAuthToken: false, }, - Listeners: []*Listener{ - &Listener{ - Type: "unix", - Config: map[string]interface{}{ - "address": "/path/to/socket", - "tls_disable": true, - "socket_mode": "configmode", - "socket_user": "configuser", - "socket_group": "configgroup", - }, - }, - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8300", - "tls_disable": true, - }, - }, - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8400", - "tls_key_file": "/path/to/cakey.pem", - "tls_cert_file": "/path/to/cacert.pem", - }, - }, - }, Vault: &Vault{ Address: "http://127.0.0.1:1111", CACert: "config_ca_cert", @@ -78,9 +76,11 @@ func TestLoadConfigFile_AgentCache(t *testing.T) { ClientCert: "config_client_cert", ClientKey: "config_client_key", }, - PidFile: "./pidfile", } + config.Listeners[0].RawConfig = nil + config.Listeners[1].RawConfig = nil + config.Listeners[2].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -91,6 +91,9 @@ func TestLoadConfigFile_AgentCache(t *testing.T) { } expected.Vault.TLSSkipVerifyRaw = interface{}(true) + config.Listeners[0].RawConfig = nil + config.Listeners[1].RawConfig = nil + config.Listeners[2].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -112,6 +115,9 @@ func TestLoadConfigFile(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -122,7 +128,7 @@ func TestLoadConfigFile(t *testing.T) { }, }, Sinks: []*Sink{ - &Sink{ + { Type: "file", DHType: "curve25519", DHPath: "/tmp/file-foo-dhpath", @@ -131,7 +137,7 @@ func TestLoadConfigFile(t *testing.T) { "path": "/tmp/file-foo", }, }, - &Sink{ + { Type: "file", WrapTTL: 5 * time.Minute, DHType: "curve25519", @@ -143,7 +149,6 @@ func TestLoadConfigFile(t *testing.T) { }, }, }, - PidFile: "./pidfile", } if diff := deep.Equal(config, expected); diff != nil { @@ -167,6 +172,9 @@ func TestLoadConfigFile_Method_Wrapping(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -177,7 +185,7 @@ func TestLoadConfigFile_Method_Wrapping(t *testing.T) { }, }, Sinks: []*Sink{ - &Sink{ + { Type: "file", Config: map[string]interface{}{ "path": "/tmp/file-foo", @@ -185,7 +193,6 @@ func TestLoadConfigFile_Method_Wrapping(t *testing.T) { }, }, }, - PidFile: "./pidfile", } if diff := deep.Equal(config, expected); diff != nil { @@ -201,18 +208,19 @@ func TestLoadConfigFile_AgentCache_NoAutoAuth(t *testing.T) { expected := &Config{ Cache: &Cache{}, - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8300", - "tls_disable": true, + SharedConfig: &configutil.SharedConfig{ + PidFile: "./pidfile", + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, }, }, }, - PidFile: "./pidfile", } + config.Listeners[0].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -267,6 +275,16 @@ func TestLoadConfigFile_AgentCache_AutoAuth_NoSink(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + }, + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -281,18 +299,9 @@ func TestLoadConfigFile_AgentCache_AutoAuth_NoSink(t *testing.T) { UseAutoAuthTokenRaw: true, ForceAutoAuthToken: false, }, - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8300", - "tls_disable": true, - }, - }, - }, - PidFile: "./pidfile", } + config.Listeners[0].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -305,6 +314,16 @@ func TestLoadConfigFile_AgentCache_AutoAuth_Force(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + }, + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -319,18 +338,9 @@ func TestLoadConfigFile_AgentCache_AutoAuth_Force(t *testing.T) { UseAutoAuthTokenRaw: "force", ForceAutoAuthToken: true, }, - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8300", - "tls_disable": true, - }, - }, - }, - PidFile: "./pidfile", } + config.Listeners[0].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -343,6 +353,16 @@ func TestLoadConfigFile_AgentCache_AutoAuth_True(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + }, + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -357,18 +377,9 @@ func TestLoadConfigFile_AgentCache_AutoAuth_True(t *testing.T) { UseAutoAuthTokenRaw: "true", ForceAutoAuthToken: false, }, - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8300", - "tls_disable": true, - }, - }, - }, - PidFile: "./pidfile", } + config.Listeners[0].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -381,6 +392,16 @@ func TestLoadConfigFile_AgentCache_AutoAuth_False(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + }, + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -390,7 +411,7 @@ func TestLoadConfigFile_AgentCache_AutoAuth_False(t *testing.T) { }, }, Sinks: []*Sink{ - &Sink{ + { Type: "file", DHType: "curve25519", DHPath: "/tmp/file-foo-dhpath", @@ -406,18 +427,9 @@ func TestLoadConfigFile_AgentCache_AutoAuth_False(t *testing.T) { UseAutoAuthTokenRaw: "false", ForceAutoAuthToken: false, }, - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8300", - "tls_disable": true, - }, - }, - }, - PidFile: "./pidfile", } + config.Listeners[0].RawConfig = nil if diff := deep.Equal(config, expected); diff != nil { t.Fatal(diff) } @@ -494,6 +506,9 @@ func TestLoadConfigFile_Template(t *testing.T) { } expected := &Config{ + SharedConfig: &configutil.SharedConfig{ + PidFile: "./pidfile", + }, AutoAuth: &AutoAuth{ Method: &Method{ Type: "aws", @@ -504,7 +519,7 @@ func TestLoadConfigFile_Template(t *testing.T) { }, }, Sinks: []*Sink{ - &Sink{ + { Type: "file", DHType: "curve25519", DHPath: "/tmp/file-foo-dhpath", @@ -516,7 +531,6 @@ func TestLoadConfigFile_Template(t *testing.T) { }, }, Templates: tc.expectedTemplates, - PidFile: "./pidfile", } if diff := deep.Equal(config, expected); diff != nil { diff --git a/command/seal_migration_test.go b/command/seal_migration_test.go index b1b94f1278..a0bb9df69b 100644 --- a/command/seal_migration_test.go +++ b/command/seal_migration_test.go @@ -547,7 +547,7 @@ func testSealMigrationTransitToShamir(t *testing.T, setup teststorage.ClusterSet // Create a Shamir seal. logger := cluster.Logger.Named("shamir") shamirSeal := vault.NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: logger, }), }) diff --git a/command/server.go b/command/server.go index ab2feccbc3..efda3dfc17 100644 --- a/command/server.go +++ b/command/server.go @@ -20,33 +20,25 @@ import ( "sync" "time" - monitoring "cloud.google.com/go/monitoring/apiv3" - "github.com/armon/go-metrics" - "github.com/armon/go-metrics/circonus" - "github.com/armon/go-metrics/datadog" - "github.com/armon/go-metrics/prometheus" - stackdriver "github.com/google/go-metrics-stackdriver" - stackdrivervault "github.com/google/go-metrics-stackdriver/vault" "github.com/hashicorp/errwrap" "github.com/hashicorp/go-hclog" log "github.com/hashicorp/go-hclog" wrapping "github.com/hashicorp/go-kms-wrapping" aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead" "github.com/hashicorp/go-multierror" - "github.com/hashicorp/go-sockaddr" "github.com/hashicorp/vault/audit" "github.com/hashicorp/vault/command/server" - serverseal "github.com/hashicorp/vault/command/server/seal" "github.com/hashicorp/vault/helper/builtinplugins" "github.com/hashicorp/vault/helper/metricsutil" "github.com/hashicorp/vault/helper/namespace" vaulthttp "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/internalshared/gatedwriter" + "github.com/hashicorp/vault/internalshared/listenerutil" "github.com/hashicorp/vault/internalshared/reloadutil" "github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/helper/mlock" - "github.com/hashicorp/vault/sdk/helper/parseutil" "github.com/hashicorp/vault/sdk/helper/useragent" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/physical" @@ -59,7 +51,6 @@ import ( "github.com/posener/complete" "go.uber.org/atomic" "golang.org/x/net/http/httpproxy" - "google.golang.org/api/option" "google.golang.org/grpc/grpclog" ) @@ -130,14 +121,6 @@ type ServerCommand struct { flagExitOnCoreShutdown bool } -type ServerListener struct { - net.Listener - config map[string]interface{} - maxRequestSize int64 - maxRequestDuration time.Duration - unauthenticatedMetricsAccess bool -} - func (c *ServerCommand) Synopsis() string { return "Start a Vault server" } @@ -497,9 +480,10 @@ func (c *ServerCommand) runRecoveryMode() int { var barrierSeal vault.Seal var sealConfigError error + var wrapper wrapping.Wrapper if len(config.Seals) == 0 { - config.Seals = append(config.Seals, &server.Seal{Type: wrapping.Shamir}) + config.Seals = append(config.Seals, &configutil.KMS{Type: wrapping.Shamir}) } if len(config.Seals) > 1 { @@ -516,13 +500,17 @@ func (c *ServerCommand) runRecoveryMode() int { sealType = configSeal.Type } + infoKeys = append(infoKeys, "Seal Type") + info["Seal Type"] = sealType + var seal vault.Seal - sealLogger := c.logger.Named(sealType) - seal, sealConfigError = serverseal.ConfigureSeal(configSeal, &infoKeys, &info, sealLogger, vault.NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + defaultSeal := vault.NewDefaultSeal(&vaultseal.Access{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: c.logger.Named("shamir"), }), - })) + }) + sealLogger := c.logger.ResetNamed(fmt.Sprintf("seal.%s", sealType)) + wrapper, sealConfigError = configutil.ConfigureWrapper(configSeal, &infoKeys, &info, sealLogger) if sealConfigError != nil { if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) { c.UI.Error(fmt.Sprintf( @@ -530,12 +518,13 @@ func (c *ServerCommand) runRecoveryMode() int { return 1 } } - if seal == nil { - c.UI.Error(fmt.Sprintf( - "After configuring seal nil returned, seal type was %s", sealType)) - return 1 + if wrapper == nil { + seal = defaultSeal + } else { + seal = vault.NewAutoSeal(&vaultseal.Access{ + Wrapper: wrapper, + }) } - barrierSeal = seal // Ensure that the seal finalizer is called, even if using verify-only @@ -579,17 +568,17 @@ func (c *ServerCommand) runRecoveryMode() int { } // Initialize the listeners - lns := make([]ServerListener, 0, len(config.Listeners)) + lns := make([]listenerutil.Listener, 0, len(config.Listeners)) for _, lnConfig := range config.Listeners { - ln, _, _, err := server.NewListener(lnConfig.Type, lnConfig.Config, c.gatedWriter, c.UI) + ln, _, _, err := server.NewListener(lnConfig, c.gatedWriter, c.UI) if err != nil { c.UI.Error(fmt.Sprintf("Error initializing listener of type %s: %s", lnConfig.Type, err)) return 1 } - lns = append(lns, ServerListener{ + lns = append(lns, listenerutil.Listener{ Listener: ln, - config: lnConfig.Config, + Config: lnConfig, }) } @@ -628,8 +617,7 @@ func (c *ServerCommand) runRecoveryMode() int { for _, ln := range lns { handler := vaulthttp.Handler(&vault.HandlerProperties{ Core: core, - MaxRequestSize: ln.maxRequestSize, - MaxRequestDuration: ln.maxRequestDuration, + ListenerConfig: ln.Config, DisablePrintableCheck: config.DisablePrintableCheck, RecoveryMode: c.flagRecovery, RecoveryToken: atomic.NewString(""), @@ -805,6 +793,7 @@ func (c *ServerCommand) Run(args []string) int { // Load the configuration var config *server.Config + var err error if c.flagDev { var devStorageType string switch { @@ -819,9 +808,13 @@ func (c *ServerCommand) Run(args []string) int { default: devStorageType = "inmem" } - config = server.DevConfig(devStorageType) + config, err = server.DevConfig(devStorageType) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } if c.flagDevListenAddr != "" { - config.Listeners[0].Config["address"] = c.flagDevListenAddr + config.Listeners[0].Address = c.flagDevListenAddr } } @@ -918,11 +911,19 @@ func (c *ServerCommand) Run(args []string) int { "in a Docker container, provide the IPC_LOCK cap to the container.")) } - metricsHelper, metricSink, err := c.setupTelemetry(config) + inmemMetrics, metricSink, prometheusEnabled, err := configutil.SetupTelemetry(&configutil.SetupTelemetryOpts{ + Config: config.Telemetry, + Ui: c.UI, + ServiceName: "vault", + DisplayName: "Vault", + UserAgent: useragent.String(), + ClusterName: config.ClusterName, + }) if err != nil { c.UI.Error(fmt.Sprintf("Error initializing telemetry: %s", err)) return 1 } + metricsHelper := metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled) // Initialize the backend factory, exists := c.PhysicalBackends[config.Storage.Type] @@ -1010,18 +1011,20 @@ func (c *ServerCommand) Run(args []string) int { var unwrapSeal vault.Seal var sealConfigError error + var wrapper wrapping.Wrapper + var barrierWrapper wrapping.Wrapper if c.flagDevAutoSeal { barrierSeal = vault.NewAutoSeal(vaultseal.NewTestSeal(nil)) } else { // Handle the case where no seal is provided switch len(config.Seals) { case 0: - config.Seals = append(config.Seals, &server.Seal{Type: wrapping.Shamir}) + config.Seals = append(config.Seals, &configutil.KMS{Type: wrapping.Shamir}) case 1: // If there's only one seal and it's disabled assume they want to // migrate to a shamir seal and simply didn't provide it if config.Seals[0].Disabled { - config.Seals = append(config.Seals, &server.Seal{Type: wrapping.Shamir}) + config.Seals = append(config.Seals, &configutil.KMS{Type: wrapping.Shamir}) } } for _, configSeal := range config.Seals { @@ -1034,13 +1037,14 @@ func (c *ServerCommand) Run(args []string) int { } var seal vault.Seal - sealLogger := c.logger.Named(sealType) + sealLogger := c.logger.ResetNamed(fmt.Sprintf("seal.%s", sealType)) allLoggers = append(allLoggers, sealLogger) - seal, sealConfigError = serverseal.ConfigureSeal(configSeal, &infoKeys, &info, sealLogger, vault.NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + defaultSeal := vault.NewDefaultSeal(&vaultseal.Access{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: c.logger.Named("shamir"), }), - })) + }) + wrapper, sealConfigError = configutil.ConfigureWrapper(configSeal, &infoKeys, &info, sealLogger) if sealConfigError != nil { if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) { c.UI.Error(fmt.Sprintf( @@ -1048,16 +1052,19 @@ func (c *ServerCommand) Run(args []string) int { return 1 } } - if seal == nil { - c.UI.Error(fmt.Sprintf( - "After configuring seal nil returned, seal type was %s", sealType)) - return 1 + if wrapper == nil { + seal = defaultSeal + } else { + seal = vault.NewAutoSeal(&vaultseal.Access{ + Wrapper: wrapper, + }) } if configSeal.Disabled { unwrapSeal = seal } else { barrierSeal = seal + barrierWrapper = wrapper } // Ensure that the seal finalizer is called, even if using verify-only @@ -1077,7 +1084,7 @@ func (c *ServerCommand) Run(args []string) int { } // prepare a secure random reader for core - secureRandomReader, err := createSecureRandomReaderFunc(config, &barrierSeal) + secureRandomReader, err := configutil.CreateSecureRandomReaderFunc(config.SharedConfig, barrierWrapper) if err != nil { c.UI.Error(err.Error()) return 1 @@ -1233,7 +1240,7 @@ func (c *ServerCommand) Run(args []string) int { } } if coreConfig.RedirectAddr == "" && c.flagDev { - coreConfig.RedirectAddr = fmt.Sprintf("http://%s", config.Listeners[0].Config["address"]) + coreConfig.RedirectAddr = fmt.Sprintf("http://%s", config.Listeners[0].Address) } // After the redirect bits are sorted out, if no cluster address was @@ -1248,7 +1255,7 @@ func (c *ServerCommand) Run(args []string) int { case coreConfig.ClusterAddr == "" && coreConfig.RedirectAddr != "": addrToUse = coreConfig.RedirectAddr case c.flagDev: - addrToUse = fmt.Sprintf("http://%s", config.Listeners[0].Config["address"]) + addrToUse = fmt.Sprintf("http://%s", config.Listeners[0].Address) default: goto CLUSTER_SYNTHESIS_COMPLETE } @@ -1366,10 +1373,10 @@ CLUSTER_SYNTHESIS_COMPLETE: clusterAddrs := []*net.TCPAddr{} // Initialize the listeners - lns := make([]ServerListener, 0, len(config.Listeners)) + lns := make([]listenerutil.Listener, 0, len(config.Listeners)) c.reloadFuncsLock.Lock() for i, lnConfig := range config.Listeners { - ln, props, reloadFunc, err := server.NewListener(lnConfig.Type, lnConfig.Config, c.gatedWriter, c.UI) + ln, props, reloadFunc, err := server.NewListener(lnConfig, c.gatedWriter, c.UI) if err != nil { c.UI.Error(fmt.Sprintf("Error initializing listener of type %s: %s", lnConfig.Type, err)) return 1 @@ -1382,12 +1389,9 @@ CLUSTER_SYNTHESIS_COMPLETE: } if !disableClustering && lnConfig.Type == "tcp" { - var addrRaw interface{} - var addr string - var ok bool - if addrRaw, ok = lnConfig.Config["cluster_address"]; ok { - addr = addrRaw.(string) - tcpAddr, err := net.ResolveTCPAddr("tcp", addr) + addr := lnConfig.ClusterAddress + if addr != "" { + tcpAddr, err := net.ResolveTCPAddr("tcp", lnConfig.ClusterAddress) if err != nil { c.UI.Error(fmt.Sprintf("Error resolving cluster_address: %s", err)) return 1 @@ -1409,59 +1413,19 @@ CLUSTER_SYNTHESIS_COMPLETE: props["cluster address"] = addr } - var maxRequestSize int64 = vaulthttp.DefaultMaxRequestSize - if valRaw, ok := lnConfig.Config["max_request_size"]; ok { - val, err := parseutil.ParseInt(valRaw) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse max_request_size value %v", valRaw)) - return 1 - } - - if val >= 0 { - maxRequestSize = val - } + if lnConfig.MaxRequestSize == 0 { + lnConfig.MaxRequestSize = vaulthttp.DefaultMaxRequestSize } - props["max_request_size"] = fmt.Sprintf("%d", maxRequestSize) + props["max_request_size"] = fmt.Sprintf("%d", lnConfig.MaxRequestSize) - maxRequestDuration := vault.DefaultMaxRequestDuration - if valRaw, ok := lnConfig.Config["max_request_duration"]; ok { - val, err := parseutil.ParseDurationSecond(valRaw) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse max_request_duration value %v", valRaw)) - return 1 - } - - if val >= 0 { - maxRequestDuration = val - } + if lnConfig.MaxRequestDuration == 0 { + lnConfig.MaxRequestDuration = vault.DefaultMaxRequestDuration } - props["max_request_duration"] = fmt.Sprintf("%s", maxRequestDuration.String()) + props["max_request_duration"] = fmt.Sprintf("%s", lnConfig.MaxRequestDuration.String()) - var unauthenticatedMetricsAccess bool - if telemetryRaw, ok := lnConfig.Config["telemetry"]; ok { - telemetry, ok := telemetryRaw.([]map[string]interface{}) - if !ok { - c.UI.Error(fmt.Sprintf("Could not parse telemetry sink value %v", telemetryRaw)) - return 1 - } - - for _, item := range telemetry { - if valRaw, ok := item["unauthenticated_metrics_access"]; ok { - unauthenticatedMetricsAccess, err = parseutil.ParseBool(valRaw) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse unauthenticated_metrics_access value %v", valRaw)) - return 1 - } - } - } - } - - lns = append(lns, ServerListener{ - Listener: ln, - config: lnConfig.Config, - maxRequestSize: maxRequestSize, - maxRequestDuration: maxRequestDuration, - unauthenticatedMetricsAccess: unauthenticatedMetricsAccess, + lns = append(lns, listenerutil.Listener{ + Listener: ln, + Config: lnConfig, }) // Store the listener props for output later @@ -1629,7 +1593,7 @@ CLUSTER_SYNTHESIS_COMPLETE: c.UI.Warn("You may need to set the following environment variable:") c.UI.Warn("") - endpointURL := "http://" + config.Listeners[0].Config["address"].(string) + endpointURL := "http://" + config.Listeners[0].Address if runtime.GOOS == "windows" { c.UI.Warn("PowerShell:") c.UI.Warn(fmt.Sprintf(" $env:VAULT_ADDR=\"%s\"", endpointURL)) @@ -1686,24 +1650,19 @@ CLUSTER_SYNTHESIS_COMPLETE: // Initialize the HTTP servers for _, ln := range lns { + if ln.Config == nil { + c.UI.Error("Found nil listener config after parsing") + return 1 + } handler := vaulthttp.Handler(&vault.HandlerProperties{ - Core: core, - MaxRequestSize: ln.maxRequestSize, - MaxRequestDuration: ln.maxRequestDuration, - DisablePrintableCheck: config.DisablePrintableCheck, - UnauthenticatedMetricsAccess: ln.unauthenticatedMetricsAccess, - RecoveryMode: c.flagRecovery, + Core: core, + ListenerConfig: ln.Config, + DisablePrintableCheck: config.DisablePrintableCheck, + RecoveryMode: c.flagRecovery, }) - // We perform validation on the config earlier, we can just cast here - if _, ok := ln.config["x_forwarded_for_authorized_addrs"]; ok { - hopSkips := ln.config["x_forwarded_for_hop_skips"].(int) - authzdAddrs := ln.config["x_forwarded_for_authorized_addrs"].([]*sockaddr.SockAddrMarshaler) - rejectNotPresent := ln.config["x_forwarded_for_reject_not_present"].(bool) - rejectNonAuthz := ln.config["x_forwarded_for_reject_not_authorized"].(bool) - if len(authzdAddrs) > 0 { - handler = vaulthttp.WrapForwardedForHandler(handler, authzdAddrs, rejectNotPresent, rejectNonAuthz, hopSkips) - } + if len(ln.Config.XForwardedForAuthorizedAddrs) > 0 { + handler = vaulthttp.WrapForwardedForHandler(handler, ln.Config) } // server defaults @@ -1716,40 +1675,17 @@ CLUSTER_SYNTHESIS_COMPLETE: } // override server defaults with config values for read/write/idle timeouts if configured - if readHeaderTimeoutInterface, ok := ln.config["http_read_header_timeout"]; ok { - readHeaderTimeout, err := parseutil.ParseDurationSecond(readHeaderTimeoutInterface) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse a time value for http_read_header_timeout %v", readHeaderTimeout)) - return 1 - } - server.ReadHeaderTimeout = readHeaderTimeout + if ln.Config.HTTPReadHeaderTimeout > 0 { + server.ReadHeaderTimeout = ln.Config.HTTPReadHeaderTimeout } - - if readTimeoutInterface, ok := ln.config["http_read_timeout"]; ok { - readTimeout, err := parseutil.ParseDurationSecond(readTimeoutInterface) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse a time value for http_read_timeout %v", readTimeout)) - return 1 - } - server.ReadTimeout = readTimeout + if ln.Config.HTTPReadTimeout > 0 { + server.ReadTimeout = ln.Config.HTTPReadTimeout } - - if writeTimeoutInterface, ok := ln.config["http_write_timeout"]; ok { - writeTimeout, err := parseutil.ParseDurationSecond(writeTimeoutInterface) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse a time value for http_write_timeout %v", writeTimeout)) - return 1 - } - server.WriteTimeout = writeTimeout + if ln.Config.HTTPWriteTimeout > 0 { + server.WriteTimeout = ln.Config.HTTPWriteTimeout } - - if idleTimeoutInterface, ok := ln.config["http_idle_timeout"]; ok { - idleTimeout, err := parseutil.ParseDurationSecond(idleTimeoutInterface) - if err != nil { - c.UI.Error(fmt.Sprintf("Could not parse a time value for http_idle_timeout %v", idleTimeout)) - return 1 - } - server.IdleTimeout = idleTimeout + if ln.Config.HTTPIdleTimeout > 0 { + server.IdleTimeout = ln.Config.HTTPIdleTimeout } // server config tests can exit now @@ -2305,24 +2241,14 @@ func (c *ServerCommand) detectRedirect(detect physical.RedirectDetect, } // Check if TLS is disabled - if val, ok := list.Config["tls_disable"]; ok { - disable, err := parseutil.ParseBool(val) - if err != nil { - return "", errwrap.Wrapf("tls_disable: {{err}}", err) - } - - if disable { - scheme = "http" - } + if list.TLSDisable { + scheme = "http" } // Check for address override - var addr string - addrRaw, ok := list.Config["address"] - if !ok { + addr := list.Address + if addr == "" { addr = "127.0.0.1:8200" - } else { - addr = addrRaw.(string) } // Check for localhost @@ -2352,165 +2278,6 @@ func (c *ServerCommand) detectRedirect(detect physical.RedirectDetect, return url.String(), nil } -// setupTelemetry is used to setup the telemetry sub-systems and returns the in-memory sink to be used in http configuration -func (c *ServerCommand) setupTelemetry(config *server.Config) (*metricsutil.MetricsHelper, *metricsutil.ClusterMetricSink, error) { - /* Setup telemetry - Aggregate on 10 second intervals for 1 minute. Expose the - metrics over stderr when there is a SIGUSR1 received. - */ - inm := metrics.NewInmemSink(10*time.Second, time.Minute) - metrics.DefaultInmemSignal(inm) - - var telConfig *server.Telemetry - if config.Telemetry != nil { - telConfig = config.Telemetry - } else { - telConfig = &server.Telemetry{} - } - - serviceName := "vault" - if telConfig.MetricsPrefix != "" { - serviceName = telConfig.MetricsPrefix - } - - metricsConf := metrics.DefaultConfig(serviceName) - metricsConf.EnableHostname = !telConfig.DisableHostname - metricsConf.EnableHostnameLabel = telConfig.EnableHostnameLabel - - // Configure the statsite sink - var fanout metrics.FanoutSink - var prometheusEnabled bool - - // Configure the Prometheus sink - if telConfig.PrometheusRetentionTime != 0 { - prometheusEnabled = true - prometheusOpts := prometheus.PrometheusOpts{ - Expiration: telConfig.PrometheusRetentionTime, - } - - sink, err := prometheus.NewPrometheusSinkFrom(prometheusOpts) - if err != nil { - return nil, nil, err - } - fanout = append(fanout, sink) - } - - metricHelper := metricsutil.NewMetricsHelper(inm, prometheusEnabled) - - if telConfig.StatsiteAddr != "" { - sink, err := metrics.NewStatsiteSink(telConfig.StatsiteAddr) - if err != nil { - return nil, nil, err - } - fanout = append(fanout, sink) - } - - // Configure the statsd sink - if telConfig.StatsdAddr != "" { - sink, err := metrics.NewStatsdSink(telConfig.StatsdAddr) - if err != nil { - return nil, nil, err - } - fanout = append(fanout, sink) - } - - // Configure the Circonus sink - if telConfig.CirconusAPIToken != "" || telConfig.CirconusCheckSubmissionURL != "" { - cfg := &circonus.Config{} - cfg.Interval = telConfig.CirconusSubmissionInterval - cfg.CheckManager.API.TokenKey = telConfig.CirconusAPIToken - cfg.CheckManager.API.TokenApp = telConfig.CirconusAPIApp - cfg.CheckManager.API.URL = telConfig.CirconusAPIURL - cfg.CheckManager.Check.SubmissionURL = telConfig.CirconusCheckSubmissionURL - cfg.CheckManager.Check.ID = telConfig.CirconusCheckID - cfg.CheckManager.Check.ForceMetricActivation = telConfig.CirconusCheckForceMetricActivation - cfg.CheckManager.Check.InstanceID = telConfig.CirconusCheckInstanceID - cfg.CheckManager.Check.SearchTag = telConfig.CirconusCheckSearchTag - cfg.CheckManager.Check.DisplayName = telConfig.CirconusCheckDisplayName - cfg.CheckManager.Check.Tags = telConfig.CirconusCheckTags - cfg.CheckManager.Broker.ID = telConfig.CirconusBrokerID - cfg.CheckManager.Broker.SelectTag = telConfig.CirconusBrokerSelectTag - - if cfg.CheckManager.API.TokenApp == "" { - cfg.CheckManager.API.TokenApp = "vault" - } - - if cfg.CheckManager.Check.DisplayName == "" { - cfg.CheckManager.Check.DisplayName = "Vault" - } - - if cfg.CheckManager.Check.SearchTag == "" { - cfg.CheckManager.Check.SearchTag = "service:vault" - } - - sink, err := circonus.NewCirconusSink(cfg) - if err != nil { - return nil, nil, err - } - sink.Start() - fanout = append(fanout, sink) - } - - if telConfig.DogStatsDAddr != "" { - var tags []string - - if telConfig.DogStatsDTags != nil { - tags = telConfig.DogStatsDTags - } - - sink, err := datadog.NewDogStatsdSink(telConfig.DogStatsDAddr, metricsConf.HostName) - if err != nil { - return nil, nil, errwrap.Wrapf("failed to start DogStatsD sink: {{err}}", err) - } - sink.SetTags(tags) - fanout = append(fanout, sink) - } - - // Configure the stackdriver sink - if telConfig.StackdriverProjectID != "" { - client, err := monitoring.NewMetricClient(context.Background(), option.WithUserAgent(useragent.String())) - if err != nil { - return nil, nil, fmt.Errorf("Failed to create stackdriver client: %v", err) - } - sink := stackdriver.NewSink(client, &stackdriver.Config{ - LabelExtractor: stackdrivervault.Extractor, - Bucketer: stackdrivervault.Bucketer, - ProjectID: telConfig.StackdriverProjectID, - Location: telConfig.StackdriverLocation, - Namespace: telConfig.StackdriverNamespace, - DebugLogs: telConfig.StackdriverDebugLogs, - }) - fanout = append(fanout, sink) - } - - // Initialize the global sink - if len(fanout) > 1 { - // Hostname enabled will create poor quality metrics name for prometheus - if !telConfig.DisableHostname { - c.UI.Warn("telemetry.disable_hostname has been set to false. Recommended setting is true for Prometheus to avoid poorly named metrics.") - } - } else { - metricsConf.EnableHostname = false - } - fanout = append(fanout, inm) - _, err := metrics.NewGlobal(metricsConf, fanout) - - if err != nil { - return nil, nil, err - } - - // Intialize a wrapper around the global sink; this will be passed to Core - // and to any backend. - wrapper := &metricsutil.ClusterMetricSink{ - ClusterName: config.ClusterName, - MaxGaugeCardinality: 500, - GaugeInterval: 10 * time.Minute, - Sink: fanout, - } - - return metricHelper, wrapper, nil -} - func (c *ServerCommand) Reload(lock *sync.RWMutex, reloadFuncs *map[string][]reloadutil.ReloadFunc, configPath []string) error { lock.RLock() defer lock.RUnlock() @@ -2522,7 +2289,7 @@ func (c *ServerCommand) Reload(lock *sync.RWMutex, reloadFuncs *map[string][]rel case strings.HasPrefix(k, "listener|"): for _, relFunc := range relFuncs { if relFunc != nil { - if err := relFunc(nil); err != nil { + if err := relFunc(); err != nil { reloadErrors = multierror.Append(reloadErrors, errwrap.Wrapf("error encountered reloading listener: {{err}}", err)) } } @@ -2531,7 +2298,7 @@ func (c *ServerCommand) Reload(lock *sync.RWMutex, reloadFuncs *map[string][]rel case strings.HasPrefix(k, "audit_file|"): for _, relFunc := range relFuncs { if relFunc != nil { - if err := relFunc(nil); err != nil { + if err := relFunc(); err != nil { reloadErrors = multierror.Append(reloadErrors, errwrap.Wrapf(fmt.Sprintf("error encountered reloading file audit device at path %q: {{err}}", strings.TrimPrefix(k, "audit_file|")), err)) } } diff --git a/command/server/config.go b/command/server/config.go index 2ad23c51b7..f757581d97 100644 --- a/command/server/config.go +++ b/command/server/config.go @@ -15,60 +15,40 @@ import ( "github.com/hashicorp/go-multierror" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/helper/parseutil" ) -const ( - prometheusDefaultRetentionTime = 24 * time.Hour -) - // Config is the configuration for the vault server. type Config struct { entConfig - Listeners []*Listener `hcl:"-"` - Storage *Storage `hcl:"-"` - HAStorage *Storage `hcl:"-"` + *configutil.SharedConfig `hcl:"-"` + + Storage *Storage `hcl:"-"` + HAStorage *Storage `hcl:"-"` ServiceRegistration *ServiceRegistration `hcl:"-"` - Seals []*Seal `hcl:"-"` - Entropy *Entropy `hcl:"-"` - CacheSize int `hcl:"cache_size"` DisableCache bool `hcl:"-"` DisableCacheRaw interface{} `hcl:"disable_cache"` - DisableMlock bool `hcl:"-"` - DisableMlockRaw interface{} `hcl:"disable_mlock"` DisablePrintableCheck bool `hcl:"-"` DisablePrintableCheckRaw interface{} `hcl:"disable_printable_check"` EnableUI bool `hcl:"-"` EnableUIRaw interface{} `hcl:"ui"` - Telemetry *Telemetry `hcl:"telemetry"` - MaxLeaseTTL time.Duration `hcl:"-"` MaxLeaseTTLRaw interface{} `hcl:"max_lease_ttl"` DefaultLeaseTTL time.Duration `hcl:"-"` DefaultLeaseTTLRaw interface{} `hcl:"default_lease_ttl"` - DefaultMaxRequestDuration time.Duration `hcl:"-"` - DefaultMaxRequestDurationRaw interface{} `hcl:"default_max_request_duration"` - - ClusterName string `hcl:"cluster_name"` ClusterCipherSuites string `hcl:"cluster_cipher_suites"` PluginDirectory string `hcl:"plugin_directory"` - LogLevel string `hcl:"log_level"` - - // LogFormat specifies the log format. Valid values are "standard" and "json". The values are case-insenstive. - // If no log format is specified, then standard format will be used. - LogFormat string `hcl:"log_format"` - - PidFile string `hcl:"pid_file"` EnableRawEndpoint bool `hcl:"-"` EnableRawEndpointRaw interface{} `hcl:"raw_storage_endpoint"` @@ -88,58 +68,36 @@ type Config struct { } // DevConfig is a Config that is used for dev mode of Vault. -func DevConfig(storageType string) *Config { - ret := &Config{ - DisableMlock: true, - EnableRawEndpoint: true, +func DevConfig(storageType string) (*Config, error) { + hclStr := ` +disable_mlock = true - Storage: &Storage{ - Type: storageType, - }, +listener "tcp" { + address = "127.0.0.1:8200" + tls_disable = true + proxy_protocol_behavior = "allow_authorized" + proxy_protocol_authorized_addrs = "127.0.0.1:8200" +} - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8200", - "tls_disable": true, - "proxy_protocol_behavior": "allow_authorized", - "proxy_protocol_authorized_addrs": "127.0.0.1:8200", - }, - }, - }, +telemetry { + prometheus_retention_time = "24h" + disable_hostname = true +} - EnableUI: true, +enable_raw_endpoint = true - Telemetry: &Telemetry{ - PrometheusRetentionTime: prometheusDefaultRetentionTime, - DisableHostname: true, - }, +storage "%s" { +} + +enable_ui = true +` + + hclStr = fmt.Sprintf(hclStr, storageType) + parsed, err := ParseConfig(hclStr) + if err != nil { + return nil, fmt.Errorf("error parsing dev config: %w", err) } - - return ret -} - -// Listener is the listener configuration for the server. -type Listener struct { - Type string - Config map[string]interface{} -} - -func (l *Listener) GoString() string { - return fmt.Sprintf("*%#v", *l) -} - -// Entropy contains Entropy configuration for the server -type EntropyMode int - -const ( - Unknown EntropyMode = iota - Augmentation -) - -type Entropy struct { - Mode EntropyMode + return parsed, nil } // Storage is the underlying storage configuration for the server. @@ -165,125 +123,10 @@ func (b *ServiceRegistration) GoString() string { return fmt.Sprintf("*%#v", *b) } -// Seal contains Seal configuration for the server -type Seal struct { - Type string - Disabled bool - Config map[string]string -} - -func (h *Seal) GoString() string { - return fmt.Sprintf("*%#v", *h) -} - -// Telemetry is the telemetry configuration for the server -type Telemetry struct { - StatsiteAddr string `hcl:"statsite_address"` - StatsdAddr string `hcl:"statsd_address"` - - DisableHostname bool `hcl:"disable_hostname"` - EnableHostnameLabel bool `hcl:"enable_hostname_label"` - MetricsPrefix string `hcl:"metrics_prefix"` - - // Circonus: see https://github.com/circonus-labs/circonus-gometrics - // for more details on the various configuration options. - // Valid configuration combinations: - // - CirconusAPIToken - // metric management enabled (search for existing check or create a new one) - // - CirconusSubmissionUrl - // metric management disabled (use check with specified submission_url, - // broker must be using a public SSL certificate) - // - CirconusAPIToken + CirconusCheckSubmissionURL - // metric management enabled (use check with specified submission_url) - // - CirconusAPIToken + CirconusCheckID - // metric management enabled (use check with specified id) - - // CirconusAPIToken is a valid API Token used to create/manage check. If provided, - // metric management is enabled. - // Default: none - CirconusAPIToken string `hcl:"circonus_api_token"` - // CirconusAPIApp is an app name associated with API token. - // Default: "consul" - CirconusAPIApp string `hcl:"circonus_api_app"` - // CirconusAPIURL is the base URL to use for contacting the Circonus API. - // Default: "https://api.circonus.com/v2" - CirconusAPIURL string `hcl:"circonus_api_url"` - // CirconusSubmissionInterval is the interval at which metrics are submitted to Circonus. - // Default: 10s - CirconusSubmissionInterval string `hcl:"circonus_submission_interval"` - // CirconusCheckSubmissionURL is the check.config.submission_url field from a - // previously created HTTPTRAP check. - // Default: none - CirconusCheckSubmissionURL string `hcl:"circonus_submission_url"` - // CirconusCheckID is the check id (not check bundle id) from a previously created - // HTTPTRAP check. The numeric portion of the check._cid field. - // Default: none - CirconusCheckID string `hcl:"circonus_check_id"` - // CirconusCheckForceMetricActivation will force enabling metrics, as they are encountered, - // if the metric already exists and is NOT active. If check management is enabled, the default - // behavior is to add new metrics as they are encountered. If the metric already exists in the - // check, it will *NOT* be activated. This setting overrides that behavior. - // Default: "false" - CirconusCheckForceMetricActivation string `hcl:"circonus_check_force_metric_activation"` - // CirconusCheckInstanceID serves to uniquely identify the metrics coming from this "instance". - // It can be used to maintain metric continuity with transient or ephemeral instances as - // they move around within an infrastructure. - // Default: hostname:app - CirconusCheckInstanceID string `hcl:"circonus_check_instance_id"` - // CirconusCheckSearchTag is a special tag which, when coupled with the instance id, helps to - // narrow down the search results when neither a Submission URL or Check ID is provided. - // Default: service:app (e.g. service:consul) - CirconusCheckSearchTag string `hcl:"circonus_check_search_tag"` - // CirconusCheckTags is a comma separated list of tags to apply to the check. Note that - // the value of CirconusCheckSearchTag will always be added to the check. - // Default: none - CirconusCheckTags string `hcl:"circonus_check_tags"` - // CirconusCheckDisplayName is the name for the check which will be displayed in the Circonus UI. - // Default: value of CirconusCheckInstanceID - CirconusCheckDisplayName string `hcl:"circonus_check_display_name"` - // CirconusBrokerID is an explicit broker to use when creating a new check. The numeric portion - // of broker._cid. If metric management is enabled and neither a Submission URL nor Check ID - // is provided, an attempt will be made to search for an existing check using Instance ID and - // Search Tag. If one is not found, a new HTTPTRAP check will be created. - // Default: use Select Tag if provided, otherwise, a random Enterprise Broker associated - // with the specified API token or the default Circonus Broker. - // Default: none - CirconusBrokerID string `hcl:"circonus_broker_id"` - // CirconusBrokerSelectTag is a special tag which will be used to select a broker when - // a Broker ID is not provided. The best use of this is to as a hint for which broker - // should be used based on *where* this particular instance is running. - // (e.g. a specific geo location or datacenter, dc:sfo) - // Default: none - CirconusBrokerSelectTag string `hcl:"circonus_broker_select_tag"` - - // Dogstats: - // DogStatsdAddr is the address of a dogstatsd instance. If provided, - // metrics will be sent to that instance - DogStatsDAddr string `hcl:"dogstatsd_addr"` - - // DogStatsdTags are the global tags that should be sent with each packet to dogstatsd - // It is a list of strings, where each string looks like "my_tag_name:my_tag_value" - DogStatsDTags []string `hcl:"dogstatsd_tags"` - - // Prometheus: - // PrometheusRetentionTime is the retention time for prometheus metrics if greater than 0. - // Default: 24h - PrometheusRetentionTime time.Duration `hcl:"-"` - PrometheusRetentionTimeRaw interface{} `hcl:"prometheus_retention_time"` - - // Stackdriver: - // StackdriverProjectID is the project to publish stackdriver metrics to. - StackdriverProjectID string `hcl:"stackdriver_project_id"` - // StackdriverLocation is the GCP or AWS region of the monitored resource. - StackdriverLocation string `hcl:"stackdriver_location"` - // StackdriverNamespace is the namespace identifier, such as a cluster name. - StackdriverNamespace string `hcl:"stackdriver_namespace"` - // StackdriverDebugLogs will write additional stackdriver related debug logs to stderr. - StackdriverDebugLogs bool `hcl:"stackdriver_debug_logs"` -} - -func (s *Telemetry) GoString() string { - return fmt.Sprintf("*%#v", *s) +func NewConfig() *Config { + return &Config{ + SharedConfig: new(configutil.SharedConfig), + } } // Merge merges two configurations. @@ -292,12 +135,11 @@ func (c *Config) Merge(c2 *Config) *Config { return c } - result := new(Config) - for _, l := range c.Listeners { - result.Listeners = append(result.Listeners, l) - } - for _, l := range c2.Listeners { - result.Listeners = append(result.Listeners, l) + result := NewConfig() + + result.SharedConfig = c.SharedConfig + if c2.SharedConfig != nil { + result.SharedConfig = c.SharedConfig.Merge(c2.SharedConfig) } result.Storage = c.Storage @@ -315,23 +157,6 @@ func (c *Config) Merge(c2 *Config) *Config { result.ServiceRegistration = c2.ServiceRegistration } - result.Entropy = c.Entropy - if c2.Entropy != nil { - result.Entropy = c2.Entropy - } - - for _, s := range c.Seals { - result.Seals = append(result.Seals, s) - } - for _, s := range c2.Seals { - result.Seals = append(result.Seals, s) - } - - result.Telemetry = c.Telemetry - if c2.Telemetry != nil { - result.Telemetry = c2.Telemetry - } - result.CacheSize = c.CacheSize if c2.CacheSize != 0 { result.CacheSize = c2.CacheSize @@ -343,11 +168,6 @@ func (c *Config) Merge(c2 *Config) *Config { result.DisableCache = c2.DisableCache } - result.DisableMlock = c.DisableMlock - if c2.DisableMlock { - result.DisableMlock = c2.DisableMlock - } - result.DisablePrintableCheck = c.DisablePrintableCheck if c2.DisablePrintableCheckRaw != nil { result.DisablePrintableCheck = c2.DisablePrintableCheck @@ -364,26 +184,6 @@ func (c *Config) Merge(c2 *Config) *Config { result.DefaultLeaseTTL = c2.DefaultLeaseTTL } - result.DefaultMaxRequestDuration = c.DefaultMaxRequestDuration - if c2.DefaultMaxRequestDuration > result.DefaultMaxRequestDuration { - result.DefaultMaxRequestDuration = c2.DefaultMaxRequestDuration - } - - result.LogLevel = c.LogLevel - if c2.LogLevel != "" { - result.LogLevel = c2.LogLevel - } - - result.LogFormat = c.LogFormat - if c2.LogFormat != "" { - result.LogFormat = c2.LogFormat - } - - result.ClusterName = c.ClusterName - if c2.ClusterName != "" { - result.ClusterName = c2.ClusterName - } - result.ClusterCipherSuites = c.ClusterCipherSuites if c2.ClusterCipherSuites != "" { result.ClusterCipherSuites = c2.ClusterCipherSuites @@ -422,11 +222,6 @@ func (c *Config) Merge(c2 *Config) *Config { result.PluginDirectory = c2.PluginDirectory } - result.PidFile = c.PidFile - if c2.PidFile != "" { - result.PidFile = c2.PidFile - } - result.DisablePerformanceStandby = c.DisablePerformanceStandby if c2.DisablePerformanceStandby { result.DisablePerformanceStandby = c2.DisablePerformanceStandby @@ -479,9 +274,26 @@ func LoadConfig(path string) (*Config, error) { } if fi.IsDir() { - return LoadConfigDir(path) + return CheckConfig(LoadConfigDir(path)) } - return LoadConfigFile(path) + return CheckConfig(LoadConfigFile(path)) +} + +func CheckConfig(c *Config, e error) (*Config, error) { + if e != nil { + return c, e + } + + if len(c.Seals) == 2 { + switch { + case c.Seals[0].Disabled && c.Seals[1].Disabled: + return nil, errors.New("seals: two seals provided but both are disabled") + case !c.Seals[0].Disabled && !c.Seals[1].Disabled: + return nil, errors.New("seals: two seals provided but neither is disabled") + } + } + + return c, nil } // LoadConfigFile loads the configuration from the given file. @@ -491,7 +303,13 @@ func LoadConfigFile(path string) (*Config, error) { if err != nil { return nil, err } - return ParseConfig(string(d)) + + conf, err := ParseConfig(string(d)) + if err != nil { + return nil, err + } + + return conf, nil } func ParseConfig(d string) (*Config, error) { @@ -502,11 +320,17 @@ func ParseConfig(d string) (*Config, error) { } // Start building the result - var result Config - if err := hcl.DecodeObject(&result, obj); err != nil { + result := NewConfig() + if err := hcl.DecodeObject(result, obj); err != nil { return nil, err } + sharedConfig, err := configutil.ParseConfig(d) + if err != nil { + return nil, err + } + result.SharedConfig = sharedConfig + if result.MaxLeaseTTLRaw != nil { if result.MaxLeaseTTL, err = parseutil.ParseDurationSecond(result.MaxLeaseTTLRaw); err != nil { return nil, err @@ -518,12 +342,6 @@ func ParseConfig(d string) (*Config, error) { } } - if result.DefaultMaxRequestDurationRaw != nil { - if result.DefaultMaxRequestDuration, err = parseutil.ParseDurationSecond(result.DefaultMaxRequestDurationRaw); err != nil { - return nil, err - } - } - if result.EnableUIRaw != nil { if result.EnableUI, err = parseutil.ParseBool(result.EnableUIRaw); err != nil { return nil, err @@ -536,12 +354,6 @@ func ParseConfig(d string) (*Config, error) { } } - if result.DisableMlockRaw != nil { - if result.DisableMlock, err = parseutil.ParseBool(result.DisableMlockRaw); err != nil { - return nil, err - } - } - if result.DisablePrintableCheckRaw != nil { if result.DisablePrintableCheck, err = parseutil.ParseBool(result.DisablePrintableCheckRaw); err != nil { return nil, err @@ -585,24 +397,24 @@ func ParseConfig(d string) (*Config, error) { // Look for storage but still support old backend if o := list.Filter("storage"); len(o.Items) > 0 { - if err := ParseStorage(&result, o, "storage"); err != nil { + if err := ParseStorage(result, o, "storage"); err != nil { return nil, errwrap.Wrapf("error parsing 'storage': {{err}}", err) } } else { if o := list.Filter("backend"); len(o.Items) > 0 { - if err := ParseStorage(&result, o, "backend"); err != nil { + if err := ParseStorage(result, o, "backend"); err != nil { return nil, errwrap.Wrapf("error parsing 'backend': {{err}}", err) } } } if o := list.Filter("ha_storage"); len(o.Items) > 0 { - if err := parseHAStorage(&result, o, "ha_storage"); err != nil { + if err := parseHAStorage(result, o, "ha_storage"); err != nil { return nil, errwrap.Wrapf("error parsing 'ha_storage': {{err}}", err) } } else { if o := list.Filter("ha_backend"); len(o.Items) > 0 { - if err := parseHAStorage(&result, o, "ha_backend"); err != nil { + if err := parseHAStorage(result, o, "ha_backend"); err != nil { return nil, errwrap.Wrapf("error parsing 'ha_backend': {{err}}", err) } } @@ -610,47 +422,17 @@ func ParseConfig(d string) (*Config, error) { // Parse service discovery if o := list.Filter("service_registration"); len(o.Items) > 0 { - if err := parseServiceRegistration(&result, o, "service_registration"); err != nil { + if err := parseServiceRegistration(result, o, "service_registration"); err != nil { return nil, errwrap.Wrapf("error parsing 'service_registration': {{err}}", err) } } - if o := list.Filter("hsm"); len(o.Items) > 0 { - if err := parseSeals(&result, o, "hsm"); err != nil { - return nil, errwrap.Wrapf("error parsing 'hsm': {{err}}", err) - } - } - - if o := list.Filter("seal"); len(o.Items) > 0 { - if err := parseSeals(&result, o, "seal"); err != nil { - return nil, errwrap.Wrapf("error parsing 'seal': {{err}}", err) - } - } - - if o := list.Filter("entropy"); len(o.Items) > 0 { - if err := parseEntropy(&result, o, "entropy"); err != nil { - return nil, errwrap.Wrapf("error parsing 'entropy': {{err}}", err) - } - } - - if o := list.Filter("listener"); len(o.Items) > 0 { - if err := parseListeners(&result, o); err != nil { - return nil, errwrap.Wrapf("error parsing 'listener': {{err}}", err) - } - } - - if o := list.Filter("telemetry"); len(o.Items) > 0 { - if err := parseTelemetry(&result, o); err != nil { - return nil, errwrap.Wrapf("error parsing 'telemetry': {{err}}", err) - } - } - entConfig := &(result.entConfig) if err := entConfig.parseConfig(list); err != nil { return nil, errwrap.Wrapf("error parsing enterprise config: {{err}}", err) } - return &result, nil + return result, nil } // LoadConfigDir loads all the configurations in the given directory @@ -702,7 +484,7 @@ func LoadConfigDir(dir string) (*Config, error) { } } - var result *Config + result := NewConfig() for _, f := range files { config, err := LoadConfigFile(f) if err != nil { @@ -902,106 +684,6 @@ func parseServiceRegistration(result *Config, list *ast.ObjectList, name string) return nil } -func parseSeals(result *Config, list *ast.ObjectList, blockName string) error { - if len(list.Items) > 2 { - return fmt.Errorf("only two or less %q blocks are permitted", blockName) - } - - seals := make([]*Seal, 0, len(list.Items)) - for _, item := range list.Items { - key := "seal" - if len(item.Keys) > 0 { - key = item.Keys[0].Token.Value().(string) - } - - var m map[string]string - if err := hcl.DecodeObject(&m, item.Val); err != nil { - return multierror.Prefix(err, fmt.Sprintf("seal.%s:", key)) - } - var disabled bool - var err error - if v, ok := m["disabled"]; ok { - disabled, err = strconv.ParseBool(v) - if err != nil { - return multierror.Prefix(err, fmt.Sprintf("%s.%s:", blockName, key)) - } - delete(m, "disabled") - } - seals = append(seals, &Seal{ - Type: strings.ToLower(key), - Disabled: disabled, - Config: m, - }) - } - - if len(seals) == 2 && - (seals[0].Disabled && seals[1].Disabled || !seals[0].Disabled && !seals[1].Disabled) { - return errors.New("seals: two seals provided but both are disabled or neither are disabled") - } - - result.Seals = seals - - return nil -} - -func parseListeners(result *Config, list *ast.ObjectList) error { - listeners := make([]*Listener, 0, len(list.Items)) - for _, item := range list.Items { - key := "listener" - if len(item.Keys) > 0 { - key = item.Keys[0].Token.Value().(string) - } - - var m map[string]interface{} - if err := hcl.DecodeObject(&m, item.Val); err != nil { - return multierror.Prefix(err, fmt.Sprintf("listeners.%s:", key)) - } - - lnType := strings.ToLower(key) - - listeners = append(listeners, &Listener{ - Type: lnType, - Config: m, - }) - } - - result.Listeners = listeners - return nil -} - -func parseTelemetry(result *Config, list *ast.ObjectList) error { - if len(list.Items) > 1 { - return fmt.Errorf("only one 'telemetry' block is permitted") - } - - // Get our one item - item := list.Items[0] - - var t Telemetry - if err := hcl.DecodeObject(&t, item.Val); err != nil { - return multierror.Prefix(err, "telemetry:") - } - - if result.Telemetry == nil { - result.Telemetry = &Telemetry{} - } - - if err := hcl.DecodeObject(&result.Telemetry, item.Val); err != nil { - return multierror.Prefix(err, "telemetry:") - } - - if result.Telemetry.PrometheusRetentionTimeRaw != nil { - var err error - if result.Telemetry.PrometheusRetentionTime, err = parseutil.ParseDurationSecond(result.Telemetry.PrometheusRetentionTimeRaw); err != nil { - return err - } - } else { - result.Telemetry.PrometheusRetentionTime = prometheusDefaultRetentionTime - } - - return nil -} - // Sanitized returns a copy of the config with all values that are considered // sensitive stripped. It also strips all `*Raw` values that are mainly // used for parsing. @@ -1012,10 +694,15 @@ func parseTelemetry(result *Config, list *ast.ObjectList) error { // - Seals.Config // - Telemetry.CirconusAPIToken func (c *Config) Sanitized() map[string]interface{} { + // Create shared config if it doesn't exist (e.g. in tests) so that map + // keys are actually populated + if c.SharedConfig == nil { + c.SharedConfig = new(configutil.SharedConfig) + } + sharedResult := c.SharedConfig.Sanitized() result := map[string]interface{}{ "cache_size": c.CacheSize, "disable_cache": c.DisableCache, - "disable_mlock": c.DisableMlock, "disable_printable_check": c.DisablePrintableCheck, "enable_ui": c.EnableUI, @@ -1023,17 +710,10 @@ func (c *Config) Sanitized() map[string]interface{} { "max_lease_ttl": c.MaxLeaseTTL, "default_lease_ttl": c.DefaultLeaseTTL, - "default_max_request_duration": c.DefaultMaxRequestDuration, - - "cluster_name": c.ClusterName, "cluster_cipher_suites": c.ClusterCipherSuites, "plugin_directory": c.PluginDirectory, - "log_level": c.LogLevel, - "log_format": c.LogFormat, - - "pid_file": c.PidFile, "raw_storage_endpoint": c.EnableRawEndpoint, "api_addr": c.APIAddr, @@ -1046,18 +726,8 @@ func (c *Config) Sanitized() map[string]interface{} { "disable_indexing": c.DisableIndexing, } - - // Sanitize listeners - if len(c.Listeners) != 0 { - var sanitizedListeners []interface{} - for _, ln := range c.Listeners { - cleanLn := map[string]interface{}{ - "type": ln.Type, - "config": ln.Config, - } - sanitizedListeners = append(sanitizedListeners, cleanLn) - } - result["listeners"] = sanitizedListeners + for k, v := range sharedResult { + result[k] = v } // Sanitize storage stanza @@ -1090,49 +760,5 @@ func (c *Config) Sanitized() map[string]interface{} { result["service_registration"] = sanitizedServiceRegistration } - // Sanitize seals stanza - if len(c.Seals) != 0 { - var sanitizedSeals []interface{} - for _, s := range c.Seals { - cleanSeal := map[string]interface{}{ - "type": s.Type, - "disabled": s.Disabled, - } - sanitizedSeals = append(sanitizedSeals, cleanSeal) - } - result["seals"] = sanitizedSeals - } - - // Sanitize telemetry stanza - if c.Telemetry != nil { - sanitizedTelemetry := map[string]interface{}{ - "statsite_address": c.Telemetry.StatsiteAddr, - "statsd_address": c.Telemetry.StatsdAddr, - "disable_hostname": c.Telemetry.DisableHostname, - "metrics_prefix": c.Telemetry.MetricsPrefix, - "circonus_api_token": "", - "circonus_api_app": c.Telemetry.CirconusAPIApp, - "circonus_api_url": c.Telemetry.CirconusAPIURL, - "circonus_submission_interval": c.Telemetry.CirconusSubmissionInterval, - "circonus_submission_url": c.Telemetry.CirconusCheckSubmissionURL, - "circonus_check_id": c.Telemetry.CirconusCheckID, - "circonus_check_force_metric_activation": c.Telemetry.CirconusCheckForceMetricActivation, - "circonus_check_instance_id": c.Telemetry.CirconusCheckInstanceID, - "circonus_check_search_tag": c.Telemetry.CirconusCheckSearchTag, - "circonus_check_tags": c.Telemetry.CirconusCheckTags, - "circonus_check_display_name": c.Telemetry.CirconusCheckDisplayName, - "circonus_broker_id": c.Telemetry.CirconusBrokerID, - "circonus_broker_select_tag": c.Telemetry.CirconusBrokerSelectTag, - "dogstatsd_addr": c.Telemetry.DogStatsDAddr, - "dogstatsd_tags": c.Telemetry.DogStatsDTags, - "prometheus_retention_time": c.Telemetry.PrometheusRetentionTime, - "stackdriver_project_id": c.Telemetry.StackdriverProjectID, - "stackdriver_location": c.Telemetry.StackdriverLocation, - "stackdriver_namespace": c.Telemetry.StackdriverNamespace, - "stackdriver_debug_logs": c.Telemetry.StackdriverDebugLogs, - } - result["telemetry"] = sanitizedTelemetry - } - return result } diff --git a/command/server/config_test_helpers.go b/command/server/config_test_helpers.go index a09e856c59..67605dd158 100644 --- a/command/server/config_test_helpers.go +++ b/command/server/config_test_helpers.go @@ -2,7 +2,6 @@ package server import ( "fmt" - "reflect" "strings" "testing" "time" @@ -10,6 +9,7 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/internalshared/configutil" ) func testConfigRaftRetryJoin(t *testing.T) { @@ -19,13 +19,14 @@ func testConfigRaftRetryJoin(t *testing.T) { } retryJoinConfig := `[{"leader_api_addr":"http://127.0.0.1:8200"},{"leader_api_addr":"http://127.0.0.2:8200"},{"leader_api_addr":"http://127.0.0.3:8200"}]` + "\n" expected := &Config{ - Listeners: []*Listener{ - { - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:8200", + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8200", }, }, + DisableMlock: true, }, Storage: &Storage{ @@ -36,26 +37,58 @@ func testConfigRaftRetryJoin(t *testing.T) { "retry_join": retryJoinConfig, }, }, - DisableMlock: true, - DisableMlockRaw: true, } - if !reflect.DeepEqual(config, expected) { - t.Fatalf("\nexpected: %#v\n actual:%#v\n", config, expected) + config.Listeners[0].RawConfig = nil + if diff := deep.Equal(config, expected); diff != nil { + t.Fatal(diff) } } -func testLoadConfigFile_topLevel(t *testing.T, entropy *Entropy) { +func testLoadConfigFile_topLevel(t *testing.T, entropy *configutil.Entropy) { config, err := LoadConfigFile("./test-fixtures/config2.hcl") if err != nil { t.Fatalf("err: %s", err) } expected := &Config{ - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:443", + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:443", + }, + }, + + Telemetry: &configutil.Telemetry{ + StatsdAddr: "bar", + StatsiteAddr: "foo", + DisableHostname: false, + DogStatsDAddr: "127.0.0.1:7254", + DogStatsDTags: []string{"tag_1:val_1", "tag_2:val_2"}, + PrometheusRetentionTime: 30 * time.Second, + }, + + DisableMlock: true, + + PidFile: "./pidfile", + + ClusterName: "testcluster", + + Seals: []*configutil.KMS{ + { + Type: "nopurpose", + }, + { + Type: "stringpurpose", + Purpose: []string{"foo"}, + }, + { + Type: "commastringpurpose", + Purpose: []string{"foo", "bar"}, + }, + { + Type: "slicepurpose", + Purpose: []string{"zip", "zap"}, }, }, }, @@ -86,20 +119,8 @@ func testLoadConfigFile_topLevel(t *testing.T, entropy *Entropy) { }, }, - Telemetry: &Telemetry{ - StatsdAddr: "bar", - StatsiteAddr: "foo", - DisableHostname: false, - DogStatsDAddr: "127.0.0.1:7254", - DogStatsDTags: []string{"tag_1:val_1", "tag_2:val_2"}, - PrometheusRetentionTime: 30 * time.Second, - PrometheusRetentionTimeRaw: "30s", - }, - DisableCache: true, DisableCacheRaw: true, - DisableMlock: true, - DisableMlockRaw: true, EnableUI: true, EnableUIRaw: true, @@ -113,9 +134,6 @@ func testLoadConfigFile_topLevel(t *testing.T, entropy *Entropy) { MaxLeaseTTLRaw: "10h", DefaultLeaseTTL: 10 * time.Hour, DefaultLeaseTTLRaw: "10h", - ClusterName: "testcluster", - - PidFile: "./pidfile", APIAddr: "top_level_api_addr", ClusterAddr: "top_level_cluster_addr", @@ -123,30 +141,49 @@ func testLoadConfigFile_topLevel(t *testing.T, entropy *Entropy) { if entropy != nil { expected.Entropy = entropy } - if !reflect.DeepEqual(config, expected) { - t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) + config.Listeners[0].RawConfig = nil + if diff := deep.Equal(config, expected); diff != nil { + t.Fatal(diff) } } -func testLoadConfigFile_json2(t *testing.T, entropy *Entropy) { +func testLoadConfigFile_json2(t *testing.T, entropy *configutil.Entropy) { config, err := LoadConfigFile("./test-fixtures/config2.hcl.json") if err != nil { t.Fatalf("err: %s", err) } expected := &Config{ - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:443", + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:443", + }, + { + Type: "tcp", + Address: "127.0.0.1:444", }, }, - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:444", - }, + + Telemetry: &configutil.Telemetry{ + StatsiteAddr: "foo", + StatsdAddr: "bar", + DisableHostname: true, + CirconusAPIToken: "0", + CirconusAPIApp: "vault", + CirconusAPIURL: "http://api.circonus.com/v2", + CirconusSubmissionInterval: "10s", + CirconusCheckSubmissionURL: "https://someplace.com/metrics", + CirconusCheckID: "0", + CirconusCheckForceMetricActivation: "true", + CirconusCheckInstanceID: "node1:vault", + CirconusCheckSearchTag: "service:vault", + CirconusCheckDisplayName: "node1:vault", + CirconusCheckTags: "cat1:tag1,cat2:tag2", + CirconusBrokerID: "0", + CirconusBrokerSelectTag: "dc:sfo", + PrometheusRetentionTime: 30 * time.Second, }, }, @@ -182,33 +219,14 @@ func testLoadConfigFile_json2(t *testing.T, entropy *Entropy) { DisableSealWrap: true, DisableSealWrapRaw: true, - - Telemetry: &Telemetry{ - StatsiteAddr: "foo", - StatsdAddr: "bar", - DisableHostname: true, - CirconusAPIToken: "0", - CirconusAPIApp: "vault", - CirconusAPIURL: "http://api.circonus.com/v2", - CirconusSubmissionInterval: "10s", - CirconusCheckSubmissionURL: "https://someplace.com/metrics", - CirconusCheckID: "0", - CirconusCheckForceMetricActivation: "true", - CirconusCheckInstanceID: "node1:vault", - CirconusCheckSearchTag: "service:vault", - CirconusCheckDisplayName: "node1:vault", - CirconusCheckTags: "cat1:tag1,cat2:tag2", - CirconusBrokerID: "0", - CirconusBrokerSelectTag: "dc:sfo", - PrometheusRetentionTime: 30 * time.Second, - PrometheusRetentionTimeRaw: "30s", - }, } if entropy != nil { expected.Entropy = entropy } - if !reflect.DeepEqual(config, expected) { - t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) + config.Listeners[0].RawConfig = nil + config.Listeners[1].RawConfig = nil + if diff := deep.Equal(config, expected); diff != nil { + t.Fatal(diff) } } @@ -216,14 +234,14 @@ func testParseEntropy(t *testing.T, oss bool) { var tests = []struct { inConfig string outErr error - outEntropy Entropy + outEntropy configutil.Entropy }{ { inConfig: `entropy "seal" { mode = "augmentation" }`, outErr: nil, - outEntropy: Entropy{Augmentation}, + outEntropy: configutil.Entropy{configutil.EntropyAugmentation}, }, { inConfig: `entropy "seal" { @@ -248,13 +266,15 @@ func testParseEntropy(t *testing.T, oss bool) { }, } - var config Config + config := Config{ + SharedConfig: &configutil.SharedConfig{}, + } for _, test := range tests { obj, _ := hcl.Parse(strings.TrimSpace(test.inConfig)) list, _ := obj.Node.(*ast.ObjectList) objList := list.Filter("entropy") - err := parseEntropy(&config, objList, "entropy") + err := configutil.ParseEntropy(config.SharedConfig, objList, "entropy") // validate the error, both should be nil or have the same Error() switch { case oss: @@ -281,13 +301,31 @@ func testLoadConfigFile(t *testing.T) { } expected := &Config{ - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:443", + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:443", }, }, + + Telemetry: &configutil.Telemetry{ + StatsdAddr: "bar", + StatsiteAddr: "foo", + DisableHostname: false, + DogStatsDAddr: "127.0.0.1:7254", + DogStatsDTags: []string{"tag_1:val_1", "tag_2:val_2"}, + PrometheusRetentionTime: configutil.PrometheusDefaultRetentionTime, + MetricsPrefix: "myprefix", + }, + + DisableMlock: true, + + Entropy: nil, + + PidFile: "./pidfile", + + ClusterName: "testcluster", }, Storage: &Storage{ @@ -314,20 +352,8 @@ func testLoadConfigFile(t *testing.T) { }, }, - Telemetry: &Telemetry{ - StatsdAddr: "bar", - StatsiteAddr: "foo", - DisableHostname: false, - DogStatsDAddr: "127.0.0.1:7254", - DogStatsDTags: []string{"tag_1:val_1", "tag_2:val_2"}, - PrometheusRetentionTime: prometheusDefaultRetentionTime, - MetricsPrefix: "myprefix", - }, - DisableCache: true, DisableCacheRaw: true, - DisableMlock: true, - DisableMlockRaw: true, DisablePrintableCheckRaw: true, DisablePrintableCheck: true, EnableUI: true, @@ -339,18 +365,14 @@ func testLoadConfigFile(t *testing.T) { DisableSealWrap: true, DisableSealWrapRaw: true, - Entropy: nil, - MaxLeaseTTL: 10 * time.Hour, MaxLeaseTTLRaw: "10h", DefaultLeaseTTL: 10 * time.Hour, DefaultLeaseTTLRaw: "10h", - ClusterName: "testcluster", - - PidFile: "./pidfile", } - if !reflect.DeepEqual(config, expected) { - t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) + config.Listeners[0].RawConfig = nil + if diff := deep.Equal(config, expected); diff != nil { + t.Fatal(diff) } } @@ -361,13 +383,37 @@ func testLoadConfigFile_json(t *testing.T) { } expected := &Config{ - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:443", + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:443", }, }, + + Telemetry: &configutil.Telemetry{ + StatsiteAddr: "baz", + StatsdAddr: "", + DisableHostname: false, + CirconusAPIToken: "", + CirconusAPIApp: "", + CirconusAPIURL: "", + CirconusSubmissionInterval: "", + CirconusCheckSubmissionURL: "", + CirconusCheckID: "", + CirconusCheckForceMetricActivation: "", + CirconusCheckInstanceID: "", + CirconusCheckSearchTag: "", + CirconusCheckDisplayName: "", + CirconusCheckTags: "", + CirconusBrokerID: "", + CirconusBrokerSelectTag: "", + PrometheusRetentionTime: configutil.PrometheusDefaultRetentionTime, + }, + + PidFile: "./pidfile", + Entropy: nil, + ClusterName: "testcluster", }, Storage: &Storage{ @@ -387,44 +433,21 @@ func testLoadConfigFile_json(t *testing.T) { ClusterCipherSuites: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - Telemetry: &Telemetry{ - StatsiteAddr: "baz", - StatsdAddr: "", - DisableHostname: false, - CirconusAPIToken: "", - CirconusAPIApp: "", - CirconusAPIURL: "", - CirconusSubmissionInterval: "", - CirconusCheckSubmissionURL: "", - CirconusCheckID: "", - CirconusCheckForceMetricActivation: "", - CirconusCheckInstanceID: "", - CirconusCheckSearchTag: "", - CirconusCheckDisplayName: "", - CirconusCheckTags: "", - CirconusBrokerID: "", - CirconusBrokerSelectTag: "", - PrometheusRetentionTime: prometheusDefaultRetentionTime, - }, - MaxLeaseTTL: 10 * time.Hour, MaxLeaseTTLRaw: "10h", DefaultLeaseTTL: 10 * time.Hour, DefaultLeaseTTLRaw: "10h", - ClusterName: "testcluster", DisableCacheRaw: interface{}(nil), - DisableMlockRaw: interface{}(nil), EnableUI: true, EnableUIRaw: true, - PidFile: "./pidfile", EnableRawEndpoint: true, EnableRawEndpointRaw: true, DisableSealWrap: true, DisableSealWrapRaw: true, - Entropy: nil, } - if !reflect.DeepEqual(config, expected) { - t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) + config.Listeners[0].RawConfig = nil + if diff := deep.Equal(config, expected); diff != nil { + t.Fatal(diff) } } @@ -435,24 +458,32 @@ func testLoadConfigDir(t *testing.T) { } expected := &Config{ - DisableCache: true, - DisableMlock: true, + SharedConfig: &configutil.SharedConfig{ + DisableMlock: true, + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:443", + }, + }, + + Telemetry: &configutil.Telemetry{ + StatsiteAddr: "qux", + StatsdAddr: "baz", + DisableHostname: true, + PrometheusRetentionTime: configutil.PrometheusDefaultRetentionTime, + }, + ClusterName: "testcluster", + }, + + DisableCache: true, DisableClustering: false, DisableClusteringRaw: false, APIAddr: "https://vault.local", ClusterAddr: "https://127.0.0.1:444", - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:443", - }, - }, - }, - Storage: &Storage{ Type: "consul", Config: map[string]string{ @@ -467,19 +498,12 @@ func testLoadConfigDir(t *testing.T) { EnableRawEndpoint: true, - Telemetry: &Telemetry{ - StatsiteAddr: "qux", - StatsdAddr: "baz", - DisableHostname: true, - PrometheusRetentionTime: prometheusDefaultRetentionTime, - }, - MaxLeaseTTL: 10 * time.Hour, DefaultLeaseTTL: 10 * time.Hour, - ClusterName: "testcluster", } - if !reflect.DeepEqual(config, expected) { - t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) + config.Listeners[0].RawConfig = nil + if diff := deep.Equal(config, expected); diff != nil { + t.Fatal(diff) } } @@ -567,6 +591,7 @@ func testConfig_Sanitized(t *testing.T) { "statsite_address": ""}, } + config.Listeners[0].RawConfig = nil if diff := deep.Equal(sanitizedConfig, expected); len(diff) > 0 { t.Fatalf("bad, diff: %#v", diff) } @@ -586,10 +611,12 @@ listener "tcp" { tls_disable_client_certs = true }`)) - var config Config + config := Config{ + SharedConfig: &configutil.SharedConfig{}, + } list, _ := obj.Node.(*ast.ObjectList) objList := list.Filter("listener") - parseListeners(&config, objList) + configutil.ParseListeners(config.SharedConfig, objList) listeners := config.Listeners if len(listeners) == 0 { t.Fatalf("expected at least one listener in the config") @@ -600,26 +627,24 @@ listener "tcp" { } expected := &Config{ - Listeners: []*Listener{ - &Listener{ - Type: "tcp", - Config: map[string]interface{}{ - "address": "127.0.0.1:443", - "cluster_address": "127.0.0.1:8201", - "tls_disable": false, - "tls_cert_file": "./certs/server.crt", - "tls_key_file": "./certs/server.key", - "tls_client_ca_file": "./certs/rootca.crt", - "tls_min_version": "tls12", - "tls_require_and_verify_client_cert": true, - "tls_disable_client_certs": true, + SharedConfig: &configutil.SharedConfig{ + Listeners: []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./certs/server.crt", + TLSKeyFile: "./certs/server.key", + TLSClientCAFile: "./certs/rootca.crt", + TLSMinVersion: "tls12", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: true, }, }, }, } - - if !reflect.DeepEqual(config, *expected) { - t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, *expected) + config.Listeners[0].RawConfig = nil + if diff := deep.Equal(config, *expected); diff != nil { + t.Fatal(diff) } - } diff --git a/command/server/config_util.go b/command/server/config_util.go index 17fe9a40eb..e4e79d3dee 100644 --- a/command/server/config_util.go +++ b/command/server/config_util.go @@ -12,7 +12,3 @@ type entConfig struct { func (ec *entConfig) parseConfig(list *ast.ObjectList) error { return nil } - -func parseEntropy(result *Config, list *ast.ObjectList, blockName string) error { - return nil -} diff --git a/command/server/listener.go b/command/server/listener.go index 3df2bfaedd..f376ba9b20 100644 --- a/command/server/listener.go +++ b/command/server/listener.go @@ -10,12 +10,13 @@ import ( "net" "github.com/hashicorp/vault/helper/proxyutil" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/internalshared/reloadutil" "github.com/mitchellh/cli" ) // ListenerFactory is the factory function to create a listener. -type ListenerFactory func(map[string]interface{}, io.Writer, cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) +type ListenerFactory func(*configutil.Listener, io.Writer, cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) // BuiltinListeners is the list of built-in listener types. var BuiltinListeners = map[string]ListenerFactory{ @@ -24,39 +25,24 @@ var BuiltinListeners = map[string]ListenerFactory{ // NewListener creates a new listener of the given type with the given // configuration. The type is looked up in the BuiltinListeners map. -func NewListener(t string, config map[string]interface{}, logger io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) { - f, ok := BuiltinListeners[t] +func NewListener(l *configutil.Listener, logger io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) { + f, ok := BuiltinListeners[l.Type] if !ok { - return nil, nil, nil, fmt.Errorf("unknown listener type: %q", t) + return nil, nil, nil, fmt.Errorf("unknown listener type: %q", l.Type) } - return f(config, logger, ui) + return f(l, logger, ui) } -func listenerWrapProxy(ln net.Listener, config map[string]interface{}) (net.Listener, error) { - behaviorRaw, ok := config["proxy_protocol_behavior"] - if !ok { +func listenerWrapProxy(ln net.Listener, l *configutil.Listener) (net.Listener, error) { + behavior := l.ProxyProtocolBehavior + if behavior == "" { return ln, nil } - behavior, ok := behaviorRaw.(string) - if !ok { - return nil, fmt.Errorf("failed parsing proxy_protocol_behavior value: not a string") - } - proxyProtoConfig := &proxyutil.ProxyProtoConfig{ - Behavior: behavior, - } - - if proxyProtoConfig.Behavior == "allow_authorized" || proxyProtoConfig.Behavior == "deny_unauthorized" { - authorizedAddrsRaw, ok := config["proxy_protocol_authorized_addrs"] - if !ok { - return nil, fmt.Errorf("proxy_protocol_behavior set but no proxy_protocol_authorized_addrs value") - } - - if err := proxyProtoConfig.SetAuthorizedAddrs(authorizedAddrsRaw); err != nil { - return nil, errwrap.Wrapf("failed parsing proxy_protocol_authorized_addrs: {{err}}", err) - } + Behavior: behavior, + AuthorizedAddrs: l.ProxyProtocolAuthorizedAddrs, } newLn, err := proxyutil.WrapInProxyProto(ln, proxyProtoConfig) diff --git a/command/server/listener_tcp.go b/command/server/listener_tcp.go index bb0be86abf..08234017ee 100644 --- a/command/server/listener_tcp.go +++ b/command/server/listener_tcp.go @@ -1,6 +1,7 @@ package server import ( + "crypto/tls" "fmt" "io" "net" @@ -8,23 +9,19 @@ import ( "strings" "time" - "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/internalshared/listenerutil" "github.com/hashicorp/vault/internalshared/reloadutil" - "github.com/hashicorp/vault/sdk/helper/parseutil" "github.com/mitchellh/cli" ) -func tcpListenerFactory(config map[string]interface{}, _ io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) { - bindProto := "tcp" - var addr string - addrRaw, ok := config["address"] - if !ok { +func tcpListenerFactory(l *configutil.Listener, _ io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) { + addr := l.Address + if addr == "" { addr = "127.0.0.1:8200" - } else { - addr = addrRaw.(string) } + bindProto := "tcp" // If they've passed 0.0.0.0, we only want to bind on IPv4 // rather than golang's dual stack default if strings.HasPrefix(addr, "0.0.0.0:") { @@ -38,67 +35,41 @@ func tcpListenerFactory(config map[string]interface{}, _ io.Writer, ui cli.Ui) ( ln = TCPKeepAliveListener{ln.(*net.TCPListener)} - ln, err = listenerWrapProxy(ln, config) + ln, err = listenerWrapProxy(ln, l) if err != nil { return nil, nil, nil, err } props := map[string]string{"addr": addr} - ffAllowedRaw, ffAllowedOK := config["x_forwarded_for_authorized_addrs"] - if ffAllowedOK { - ffAllowed, err := parseutil.ParseAddrs(ffAllowedRaw) - if err != nil { - return nil, nil, nil, errwrap.Wrapf("error parsing \"x_forwarded_for_authorized_addrs\": {{err}}", err) + // X-Forwarded-For props + { + if len(l.XForwardedForAuthorizedAddrs) > 0 { + props["x_forwarded_for_authorized_addrs"] = fmt.Sprintf("%v", l.XForwardedForAuthorizedAddrs) + } + + if l.XForwardedForHopSkips > 0 { + props["x_forwarded_for_hop_skips"] = fmt.Sprintf("%d", l.XForwardedForHopSkips) + } else if len(l.XForwardedForAuthorizedAddrs) > 0 { + props["x_forwarded_for_hop_skips"] = "0" + } + + if len(l.XForwardedForAuthorizedAddrs) > 0 { + props["x_forwarded_for_reject_not_present"] = strconv.FormatBool(l.XForwardedForRejectNotPresent) + } + + if len(l.XForwardedForAuthorizedAddrs) > 0 { + props["x_forwarded_for_reject_not_authorized"] = strconv.FormatBool(l.XForwardedForRejectNotAuthorized) } - props["x_forwarded_for_authorized_addrs"] = fmt.Sprintf("%v", ffAllowed) - config["x_forwarded_for_authorized_addrs"] = ffAllowed } - if ffHopsRaw, ok := config["x_forwarded_for_hop_skips"]; ok { - ffHops64, err := parseutil.ParseInt(ffHopsRaw) - if err != nil { - return nil, nil, nil, errwrap.Wrapf("error parsing \"x_forwarded_for_hop_skips\": {{err}}", err) - } - if ffHops64 < 0 { - return nil, nil, nil, fmt.Errorf("\"x_forwarded_for_hop_skips\" cannot be negative") - } - ffHops := int(ffHops64) - props["x_forwarded_for_hop_skips"] = strconv.Itoa(ffHops) - config["x_forwarded_for_hop_skips"] = ffHops - } else if ffAllowedOK { - props["x_forwarded_for_hop_skips"] = "0" - config["x_forwarded_for_hop_skips"] = int(0) - } - - if ffRejectNotPresentRaw, ok := config["x_forwarded_for_reject_not_present"]; ok { - ffRejectNotPresent, err := parseutil.ParseBool(ffRejectNotPresentRaw) - if err != nil { - return nil, nil, nil, errwrap.Wrapf("error parsing \"x_forwarded_for_reject_not_present\": {{err}}", err) - } - props["x_forwarded_for_reject_not_present"] = strconv.FormatBool(ffRejectNotPresent) - config["x_forwarded_for_reject_not_present"] = ffRejectNotPresent - } else if ffAllowedOK { - props["x_forwarded_for_reject_not_present"] = "true" - config["x_forwarded_for_reject_not_present"] = true - } - - if ffRejectNonAuthorizedRaw, ok := config["x_forwarded_for_reject_not_authorized"]; ok { - ffRejectNonAuthorized, err := parseutil.ParseBool(ffRejectNonAuthorizedRaw) - if err != nil { - return nil, nil, nil, errwrap.Wrapf("error parsing \"x_forwarded_for_reject_not_authorized\": {{err}}", err) - } - props["x_forwarded_for_reject_not_authorized"] = strconv.FormatBool(ffRejectNonAuthorized) - config["x_forwarded_for_reject_not_authorized"] = ffRejectNonAuthorized - } else if ffAllowedOK { - props["x_forwarded_for_reject_not_authorized"] = "true" - config["x_forwarded_for_reject_not_authorized"] = true - } - - ln, props, reloadFunc, _, err := listenerutil.WrapTLS(ln, props, config, ui) + tlsConfig, reloadFunc, err := listenerutil.TLSConfig(l, props, ui) if err != nil { return nil, nil, nil, err } + if tlsConfig != nil { + ln = tls.NewListener(ln, tlsConfig) + } return ln, props, reloadFunc, nil } diff --git a/command/server/listener_tcp_test.go b/command/server/listener_tcp_test.go index 95e516274c..c503d427e8 100644 --- a/command/server/listener_tcp_test.go +++ b/command/server/listener_tcp_test.go @@ -11,13 +11,14 @@ import ( "testing" "time" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/mitchellh/cli" ) func TestTCPListener(t *testing.T) { - ln, _, _, err := tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_disable": "1", + ln, _, _, err := tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSDisable: true, }, nil, cli.NewMockUi()) if err != nil { t.Fatalf("err: %s", err) @@ -49,12 +50,12 @@ func TestTCPListener_tls(t *testing.T) { t.Fatal("not ok when appending CA cert") } - ln, _, _, err := tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_cert_file": wd + "reload_foo.pem", - "tls_key_file": wd + "reload_foo.key", - "tls_require_and_verify_client_cert": "true", - "tls_client_ca_file": wd + "reload_ca.pem", + ln, _, _, err := tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSCertFile: wd + "reload_foo.pem", + TLSKeyFile: wd + "reload_foo.key", + TLSRequireAndVerifyClientCert: true, + TLSClientCAFile: wd + "reload_ca.pem", }, nil, cli.NewMockUi()) if err != nil { t.Fatalf("err: %s", err) @@ -87,24 +88,24 @@ func TestTCPListener_tls(t *testing.T) { testListenerImpl(t, ln, connFn(true), "foo.example.com") - ln, _, _, err = tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_cert_file": wd + "reload_foo.pem", - "tls_key_file": wd + "reload_foo.key", - "tls_require_and_verify_client_cert": "true", - "tls_disable_client_certs": "true", - "tls_client_ca_file": wd + "reload_ca.pem", + ln, _, _, err = tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSCertFile: wd + "reload_foo.pem", + TLSKeyFile: wd + "reload_foo.key", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: true, + TLSClientCAFile: wd + "reload_ca.pem", }, nil, cli.NewMockUi()) if err == nil { t.Fatal("expected error due to mutually exclusive client cert options") } - ln, _, _, err = tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_cert_file": wd + "reload_foo.pem", - "tls_key_file": wd + "reload_foo.key", - "tls_disable_client_certs": "true", - "tls_client_ca_file": wd + "reload_ca.pem", + ln, _, _, err = tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSCertFile: wd + "reload_foo.pem", + TLSKeyFile: wd + "reload_foo.key", + TLSDisableClientCerts: true, + TLSClientCAFile: wd + "reload_ca.pem", }, nil, cli.NewMockUi()) if err != nil { t.Fatalf("err: %s", err) @@ -131,13 +132,13 @@ func TestTCPListener_tls13(t *testing.T) { t.Fatal("not ok when appending CA cert") } - ln, _, _, err := tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_cert_file": wd + "reload_foo.pem", - "tls_key_file": wd + "reload_foo.key", - "tls_require_and_verify_client_cert": "true", - "tls_client_ca_file": wd + "reload_ca.pem", - "tls_min_version": "tls13", + ln, _, _, err := tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSCertFile: wd + "reload_foo.pem", + TLSKeyFile: wd + "reload_foo.key", + TLSRequireAndVerifyClientCert: true, + TLSClientCAFile: wd + "reload_ca.pem", + TLSMinVersion: "tls13", }, nil, cli.NewMockUi()) if err != nil { t.Fatalf("err: %s", err) @@ -170,26 +171,26 @@ func TestTCPListener_tls13(t *testing.T) { testListenerImpl(t, ln, connFn(true), "foo.example.com") - ln, _, _, err = tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_cert_file": wd + "reload_foo.pem", - "tls_key_file": wd + "reload_foo.key", - "tls_require_and_verify_client_cert": "true", - "tls_disable_client_certs": "true", - "tls_client_ca_file": wd + "reload_ca.pem", - "tls_min_version": "tls13", + ln, _, _, err = tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSCertFile: wd + "reload_foo.pem", + TLSKeyFile: wd + "reload_foo.key", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: true, + TLSClientCAFile: wd + "reload_ca.pem", + TLSMinVersion: "tls13", }, nil, cli.NewMockUi()) if err == nil { t.Fatal("expected error due to mutually exclusive client cert options") } - ln, _, _, err = tcpListenerFactory(map[string]interface{}{ - "address": "127.0.0.1:0", - "tls_cert_file": wd + "reload_foo.pem", - "tls_key_file": wd + "reload_foo.key", - "tls_disable_client_certs": "true", - "tls_client_ca_file": wd + "reload_ca.pem", - "tls_min_version": "tls13", + ln, _, _, err = tcpListenerFactory(&configutil.Listener{ + Address: "127.0.0.1:0", + TLSCertFile: wd + "reload_foo.pem", + TLSKeyFile: wd + "reload_foo.key", + TLSDisableClientCerts: true, + TLSClientCAFile: wd + "reload_ca.pem", + TLSMinVersion: "tls13", }, nil, cli.NewMockUi()) if err != nil { t.Fatalf("err: %s", err) diff --git a/command/server/seal/server_seal.go b/command/server/seal/server_seal.go deleted file mode 100644 index 9cdb3c581e..0000000000 --- a/command/server/seal/server_seal.go +++ /dev/null @@ -1,45 +0,0 @@ -package seal - -import ( - "fmt" - - "github.com/hashicorp/go-hclog" - wrapping "github.com/hashicorp/go-kms-wrapping" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/vault" -) - -var ( - ConfigureSeal = configureSeal -) - -func configureSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger hclog.Logger, inseal vault.Seal) (outseal vault.Seal, err error) { - switch configSeal.Type { - case wrapping.AliCloudKMS: - return configureAliCloudKMSSeal(configSeal, infoKeys, info, logger, inseal) - - case wrapping.AWSKMS: - return configureAWSKMSSeal(configSeal, infoKeys, info, logger, inseal) - - case wrapping.AzureKeyVault: - return configureAzureKeyVaultSeal(configSeal, infoKeys, info, logger, inseal) - - case wrapping.GCPCKMS: - return configureGCPCKMSSeal(configSeal, infoKeys, info, logger, inseal) - - case wrapping.OCIKMS: - return configureOCIKMSSeal(configSeal, infoKeys, info, logger, inseal) - - case wrapping.Transit: - return configureTransitSeal(configSeal, infoKeys, info, logger, inseal) - - case wrapping.PKCS11: - return nil, fmt.Errorf("Seal type 'pkcs11' requires the Vault Enterprise HSM binary") - - case wrapping.Shamir: - return inseal, nil - - default: - return nil, fmt.Errorf("Unknown seal type %q", configSeal.Type) - } -} diff --git a/command/server/seal/server_seal_alicloudkms.go b/command/server/seal/server_seal_alicloudkms.go deleted file mode 100644 index 269aab56da..0000000000 --- a/command/server/seal/server_seal_alicloudkms.go +++ /dev/null @@ -1,36 +0,0 @@ -package seal - -import ( - "github.com/hashicorp/errwrap" - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/sdk/logical" - "github.com/hashicorp/vault/vault" - "github.com/hashicorp/vault/vault/seal" -) - -func configureAliCloudKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) { - kms := alicloudkms.NewWrapper(nil) - kmsInfo, err := kms.SetConfig(configSeal.Config) - if err != nil { - // If the error is any other than logical.KeyNotFoundError, return the error - if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { - return nil, err - } - } - autoseal := vault.NewAutoSeal(&seal.Access{ - Wrapper: kms, - }) - if kmsInfo != nil { - *infoKeys = append(*infoKeys, "Seal Type", "AliCloud KMS Region", "AliCloud KMS KeyID") - (*info)["Seal Type"] = configSeal.Type - (*info)["AliCloud KMS Region"] = kmsInfo["region"] - (*info)["AliCloud KMS KeyID"] = kmsInfo["kms_key_id"] - if domain, ok := kmsInfo["domain"]; ok { - *infoKeys = append(*infoKeys, "AliCloud KMS Domain") - (*info)["AliCloud KMS Domain"] = domain - } - } - return autoseal, nil -} diff --git a/command/server/seal/server_seal_awskms.go b/command/server/seal/server_seal_awskms.go deleted file mode 100644 index 173fbaadf7..0000000000 --- a/command/server/seal/server_seal_awskms.go +++ /dev/null @@ -1,42 +0,0 @@ -package seal - -import ( - "github.com/hashicorp/errwrap" - "github.com/hashicorp/go-hclog" - wrapping "github.com/hashicorp/go-kms-wrapping" - "github.com/hashicorp/go-kms-wrapping/wrappers/awskms" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/sdk/logical" - "github.com/hashicorp/vault/vault" - "github.com/hashicorp/vault/vault/seal" -) - -var getAWSKMSFunc = func(opts *wrapping.WrapperOptions, config map[string]string) (wrapping.Wrapper, map[string]string, error) { - kms := awskms.NewWrapper(nil) - kmsInfo, err := kms.SetConfig(config) - return kms, kmsInfo, err -} - -func configureAWSKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger hclog.Logger, inseal vault.Seal) (vault.Seal, error) { - kms, kmsInfo, err := getAWSKMSFunc(nil, configSeal.Config) - if err != nil { - // If the error is any other than logical.KeyNotFoundError, return the error - if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { - return nil, err - } - } - autoseal := vault.NewAutoSeal(&seal.Access{ - Wrapper: kms, - }) - if kmsInfo != nil { - *infoKeys = append(*infoKeys, "Seal Type", "AWS KMS Region", "AWS KMS KeyID") - (*info)["Seal Type"] = configSeal.Type - (*info)["AWS KMS Region"] = kmsInfo["region"] - (*info)["AWS KMS KeyID"] = kmsInfo["kms_key_id"] - if endpoint, ok := kmsInfo["endpoint"]; ok { - *infoKeys = append(*infoKeys, "AWS KMS Endpoint") - (*info)["AWS KMS Endpoint"] = endpoint - } - } - return autoseal, nil -} diff --git a/command/server/seal/server_seal_azurekeyvault.go b/command/server/seal/server_seal_azurekeyvault.go deleted file mode 100644 index 4b26c29ea6..0000000000 --- a/command/server/seal/server_seal_azurekeyvault.go +++ /dev/null @@ -1,33 +0,0 @@ -package seal - -import ( - "github.com/hashicorp/errwrap" - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/sdk/logical" - "github.com/hashicorp/vault/vault" - "github.com/hashicorp/vault/vault/seal" -) - -func configureAzureKeyVaultSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) { - kv := azurekeyvault.NewWrapper(nil) - kvInfo, err := kv.SetConfig(configSeal.Config) - if err != nil { - // If the error is any other than logical.KeyNotFoundError, return the error - if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { - return nil, err - } - } - autoseal := vault.NewAutoSeal(&seal.Access{ - Wrapper: kv, - }) - if kvInfo != nil { - *infoKeys = append(*infoKeys, "Seal Type", "Azure Environment", "Azure Vault Name", "Azure Key Name") - (*info)["Seal Type"] = configSeal.Type - (*info)["Azure Environment"] = kvInfo["environment"] - (*info)["Azure Vault Name"] = kvInfo["vault_name"] - (*info)["Azure Key Name"] = kvInfo["key_name"] - } - return autoseal, nil -} diff --git a/command/server/seal/server_seal_gcpckms.go b/command/server/seal/server_seal_gcpckms.go deleted file mode 100644 index c33c173df8..0000000000 --- a/command/server/seal/server_seal_gcpckms.go +++ /dev/null @@ -1,44 +0,0 @@ -package seal - -import ( - "github.com/hashicorp/errwrap" - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/sdk/helper/useragent" - "github.com/hashicorp/vault/sdk/logical" - "github.com/hashicorp/vault/vault" - "github.com/hashicorp/vault/vault/seal" -) - -func configureGCPCKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) { - // The config map can be nil if all other seal params were provided via env - // vars so we nil check here before setting user_agent down below. - if configSeal.Config == nil { - configSeal.Config = map[string]string{} - } - // This is not exposed at the moment so we always override user_agent - // with Vault's internal value. - configSeal.Config["user_agent"] = useragent.String() - - kms := gcpckms.NewWrapper(nil) - kmsInfo, err := kms.SetConfig(configSeal.Config) - if err != nil { - // If the error is any other than logical.KeyNotFoundError, return the error - if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { - return nil, err - } - } - autoseal := vault.NewAutoSeal(&seal.Access{ - Wrapper: kms, - }) - if kmsInfo != nil { - *infoKeys = append(*infoKeys, "Seal Type", "GCP KMS Project", "GCP KMS Region", "GCP KMS Key Ring", "GCP KMS Crypto Key") - (*info)["Seal Type"] = configSeal.Type - (*info)["GCP KMS Project"] = kmsInfo["project"] - (*info)["GCP KMS Region"] = kmsInfo["region"] - (*info)["GCP KMS Key Ring"] = kmsInfo["key_ring"] - (*info)["GCP KMS Crypto Key"] = kmsInfo["crypto_key"] - } - return autoseal, nil -} diff --git a/command/server/seal/server_seal_ocikms.go b/command/server/seal/server_seal_ocikms.go deleted file mode 100644 index 7c4ff26c97..0000000000 --- a/command/server/seal/server_seal_ocikms.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright © 2019, Oracle and/or its affiliates. -package seal - -import ( - log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-kms-wrapping/wrappers/ocikms" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/vault" - "github.com/hashicorp/vault/vault/seal" -) - -func configureOCIKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) { - kms := ocikms.NewWrapper(nil) - kmsInfo, err := kms.SetConfig(configSeal.Config) - if err != nil { - logger.Error("error on setting up config for OCI KMS", "error", err) - return nil, err - } - autoseal := vault.NewAutoSeal(&seal.Access{ - Wrapper: kms, - }) - if kmsInfo != nil { - *infoKeys = append(*infoKeys, "Seal Type", "OCI KMS KeyID") - (*info)["Seal Type"] = configSeal.Type - (*info)["OCI KMS KeyID"] = kmsInfo[ocikms.KMSConfigKeyID] - (*info)["OCI KMS Crypto Endpoint"] = kmsInfo[ocikms.KMSConfigCryptoEndpoint] - (*info)["OCI KMS Management Endpoint"] = kmsInfo[ocikms.KMSConfigManagementEndpoint] - (*info)["OCI KMS Principal Type"] = kmsInfo["principal_type"] - } - return autoseal, nil -} diff --git a/command/server/seal/server_seal_transit.go b/command/server/seal/server_seal_transit.go deleted file mode 100644 index e8838d98a3..0000000000 --- a/command/server/seal/server_seal_transit.go +++ /dev/null @@ -1,46 +0,0 @@ -package seal - -import ( - "github.com/hashicorp/errwrap" - log "github.com/hashicorp/go-hclog" - wrapping "github.com/hashicorp/go-kms-wrapping" - "github.com/hashicorp/go-kms-wrapping/wrappers/transit" - "github.com/hashicorp/vault/command/server" - "github.com/hashicorp/vault/sdk/logical" - "github.com/hashicorp/vault/vault" - "github.com/hashicorp/vault/vault/seal" -) - -var GetTransitKMSFunc = func(opts *wrapping.WrapperOptions, config map[string]string) (wrapping.Wrapper, map[string]string, error) { - transitSeal := transit.NewWrapper(opts) - sealInfo, err := transitSeal.SetConfig(config) - return transitSeal, sealInfo, err -} - -func configureTransitSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) { - transitSeal, sealInfo, err := GetTransitKMSFunc( - &wrapping.WrapperOptions{ - Logger: logger.ResetNamed("seal-transit"), - }, configSeal.Config) - if err != nil { - // If the error is any other than logical.KeyNotFoundError, return the error - if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { - return nil, err - } - } - autoseal := vault.NewAutoSeal(&seal.Access{ - Wrapper: transitSeal, - }) - if sealInfo != nil { - *infoKeys = append(*infoKeys, "Seal Type", "Transit Address", "Transit Mount Path", "Transit Key Name") - (*info)["Seal Type"] = configSeal.Type - (*info)["Transit Address"] = sealInfo["address"] - (*info)["Transit Mount Path"] = sealInfo["mount_path"] - (*info)["Transit Key Name"] = sealInfo["key_name"] - if namespace, ok := sealInfo["namespace"]; ok { - *infoKeys = append(*infoKeys, "Transit Namespace") - (*info)["Transit Namespace"] = namespace - } - } - return autoseal, nil -} diff --git a/command/server/seal/server_seal_transit_acc_test.go b/command/server/server_seal_transit_acc_test.go similarity index 89% rename from command/server/seal/server_seal_transit_acc_test.go rename to command/server/server_seal_transit_acc_test.go index 357d9208bb..b895edaf6d 100644 --- a/command/server/seal/server_seal_transit_acc_test.go +++ b/command/server/server_seal_transit_acc_test.go @@ -1,4 +1,4 @@ -package seal_test +package server import ( "context" @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/api" - "github.com/hashicorp/vault/command/server/seal" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/ory/dockertest" ) @@ -26,19 +26,19 @@ func TestTransitWrapper_Lifecycle(t *testing.T) { "key_name": keyName, } - s, _, err := seal.GetTransitKMSFunc(nil, wrapperConfig) + kms, _, err := configutil.GetTransitKMSFunc(nil, &configutil.KMS{Config: wrapperConfig}) if err != nil { t.Fatalf("error setting wrapper config: %v", err) } // Test Encrypt and Decrypt calls input := []byte("foo") - swi, err := s.Encrypt(context.Background(), input, nil) + swi, err := kms.Encrypt(context.Background(), input, nil) if err != nil { t.Fatalf("err: %s", err.Error()) } - pt, err := s.Decrypt(context.Background(), swi, nil) + pt, err := kms.Decrypt(context.Background(), swi, nil) if err != nil { t.Fatalf("err: %s", err.Error()) } @@ -79,7 +79,7 @@ func TestTransitSeal_TokenRenewal(t *testing.T) { "mount_path": mountPath, "key_name": keyName, } - s, _, err := seal.GetTransitKMSFunc(nil, wrapperConfig) + kms, _, err := configutil.GetTransitKMSFunc(nil, &configutil.KMS{Config: wrapperConfig}) if err != nil { t.Fatalf("error setting wrapper config: %v", err) } @@ -88,12 +88,12 @@ func TestTransitSeal_TokenRenewal(t *testing.T) { // Test Encrypt and Decrypt calls input := []byte("foo") - swi, err := s.Encrypt(context.Background(), input, nil) + swi, err := kms.Encrypt(context.Background(), input, nil) if err != nil { t.Fatalf("err: %s", err.Error()) } - pt, err := s.Decrypt(context.Background(), swi, nil) + pt, err := kms.Decrypt(context.Background(), swi, nil) if err != nil { t.Fatalf("err: %s", err.Error()) } diff --git a/command/server/test-fixtures/config.hcl b/command/server/test-fixtures/config.hcl index 84639db669..de77798bbf 100644 --- a/command/server/test-fixtures/config.hcl +++ b/command/server/test-fixtures/config.hcl @@ -5,6 +5,7 @@ ui = true listener "tcp" { address = "127.0.0.1:443" + allow_stuff = true } backend "consul" { diff --git a/command/server/test-fixtures/config2.hcl b/command/server/test-fixtures/config2.hcl index 33244e54e8..c950788c74 100644 --- a/command/server/test-fixtures/config2.hcl +++ b/command/server/test-fixtures/config2.hcl @@ -37,6 +37,18 @@ entropy "seal" { mode = "augmentation" } +kms "commastringpurpose" { + purpose = "foo,bar" +} +kms "slicepurpose" { + purpose = ["zip", "zap"] +} +seal "nopurpose" { +} +seal "stringpurpose" { + purpose = "foo" +} + max_lease_ttl = "10h" default_lease_ttl = "10h" cluster_name = "testcluster" diff --git a/command/server_test.go b/command/server_test.go index cddbdd5ae7..72bc6e5605 100644 --- a/command/server_test.go +++ b/command/server_test.go @@ -230,28 +230,28 @@ func TestServer(t *testing.T) { { "bad_listener_read_header_timeout_config", testBaseHCL(t, badListenerReadHeaderTimeout) + inmemHCL, - "Could not parse a time value for http_read_header_timeout", + "unknown unit km in duration 12km", 1, "-test-server-config", }, { "bad_listener_read_timeout_config", testBaseHCL(t, badListenerReadTimeout) + inmemHCL, - "Could not parse a time value for http_read_timeout", + "parsing \"34日\": invalid syntax", 1, "-test-server-config", }, { "bad_listener_write_timeout_config", testBaseHCL(t, badListenerWriteTimeout) + inmemHCL, - "Could not parse a time value for http_write_timeout", + "unknown unit lbs in duration 56lbs", 1, "-test-server-config", }, { "bad_listener_idle_timeout_config", testBaseHCL(t, badListenerIdleTimeout) + inmemHCL, - "Could not parse a time value for http_idle_timeout", + "unknown unit gophers in duration 78gophers", 1, "-test-server-config", }, diff --git a/command/server_util.go b/command/server_util.go index 8e6b5cff14..1f3819a34b 100644 --- a/command/server_util.go +++ b/command/server_util.go @@ -2,9 +2,7 @@ package command import ( "context" - "crypto/rand" "fmt" - "io" log "github.com/hashicorp/go-hclog" wrapping "github.com/hashicorp/go-kms-wrapping" @@ -16,17 +14,12 @@ import ( ) var ( - createSecureRandomReaderFunc = createSecureRandomReader - adjustCoreConfigForEnt = adjustCoreConfigForEntNoop + adjustCoreConfigForEnt = adjustCoreConfigForEntNoop ) func adjustCoreConfigForEntNoop(config *server.Config, coreConfig *vault.CoreConfig) { } -func createSecureRandomReader(config *server.Config, seal *vault.Seal) (io.Reader, error) { - return rand.Reader, nil -} - func adjustCoreForSealMigration(logger log.Logger, core *vault.Core, barrierSeal, unwrapSeal vault.Seal) error { existBarrierSealConfig, existRecoverySealConfig, err := core.PhysicalSealConfigs(context.Background()) if err != nil { @@ -70,7 +63,7 @@ func adjustCoreForSealMigration(logger log.Logger, core *vault.Core, barrierSeal case wrapping.Shamir: // The value reflected in config is what we're going to migrationSeal = vault.NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: logger.Named("shamir"), }), }) diff --git a/go.mod b/go.mod index 8eec268928..36700b407d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ replace github.com/hashicorp/vault/sdk => ./sdk require ( cloud.google.com/go v0.39.0 github.com/Azure/azure-sdk-for-go v36.2.0+incompatible - github.com/Azure/go-autorest/autorest v0.9.2 + github.com/Azure/go-autorest/autorest v0.9.6 github.com/DataDog/zstd v1.4.4 // indirect github.com/NYTimes/gziphandler v1.1.1 github.com/SAP/go-hdb v0.14.1 @@ -43,7 +43,7 @@ require ( github.com/go-test/deep v1.0.2 github.com/gocql/gocql v0.0.0-20190402132108-0e1d5de854df github.com/gogo/protobuf v1.2.1 - github.com/golang/protobuf v1.3.2 + github.com/golang/protobuf v1.3.4 github.com/google/go-github v17.0.0+incompatible github.com/google/go-metrics-stackdriver v0.2.0 github.com/hashicorp/consul-template v0.22.0 @@ -51,8 +51,8 @@ require ( github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-gcp-common v0.6.0 - github.com/hashicorp/go-hclog v0.12.0 - github.com/hashicorp/go-kms-wrapping v0.5.1 + github.com/hashicorp/go-hclog v0.12.1 + github.com/hashicorp/go-kms-wrapping v0.5.5 github.com/hashicorp/go-memdb v1.0.2 github.com/hashicorp/go-msgpack v0.5.5 github.com/hashicorp/go-multierror v1.0.0 @@ -86,8 +86,8 @@ require ( github.com/hashicorp/vault-plugin-secrets-kv v0.5.5 github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2 github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2 - github.com/hashicorp/vault/api v1.0.5-0.20200317185738-82f498082f02 - github.com/hashicorp/vault/sdk v0.1.14-0.20200317185738-82f498082f02 + github.com/hashicorp/vault/api v1.0.5-0.20200425175256-972b211f3e96 + github.com/hashicorp/vault/sdk v0.1.14-0.20200425175256-972b211f3e96 github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4 github.com/jcmturner/gokrb5/v8 v8.0.0 github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f diff --git a/go.sum b/go.sum index e6eeb2dad4..8bfedf89bc 100644 --- a/go.sum +++ b/go.sum @@ -12,16 +12,23 @@ github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.2 h1:6AWuh3uWrsZJcNoCHrCF/+g4aKPCU39kaMO6/qrnK/4= github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6 h1:5YWtOnckcudzIw8lPPBcWOnmIFWMtHci1ZWAZulMSx0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.6.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.7.0 h1:PUMxSVw3tEImG0JTRqbxjXLKCSoPk7DartDELqlOuiI= github.com/Azure/go-autorest/autorest/adal v0.7.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/azure/auth v0.4.0 h1:18ld/uw9Rr7VkNie7a7RMAcFIWrJdlUL59TWGfcu530= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/azure/auth v0.4.0/go.mod h1:Oo5cRhLvZteXzI2itUm5ziqsoIxRkzrt3t61FeZaS18= -github.com/Azure/go-autorest/autorest/azure/cli v0.3.0 h1:5PAqnv+CSTwW9mlZWZAizmzrazFWEgZykEZXpr2hDtY= +github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk= +github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/cli v0.3.0/go.mod h1:rNYMNAefZMRowqCV0cVhr/YDW5dD7afFq9nXAXL4ykE= +github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U= +github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= @@ -81,7 +88,6 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= -github.com/armon/go-metrics v0.3.0 h1:B7AQgHi8QSEi4uHu7Sbsga+IJDU+CENgjxoo81vDUqU= github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-metrics v0.3.3 h1:a9F4rlj7EWWrbj7BYw8J8+x+ZZkJeqzNyRk8hdPF+ro= github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= @@ -97,9 +103,7 @@ github.com/aws/aws-sdk-go v1.25.41 h1:/hj7nZ0586wFqpwjNpzWiUTwtaMgxAZNZKHay80MdX github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -144,17 +148,14 @@ github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.0.0+incompatible h1:+RStIopZ8wooMx+Vs5Bt8zMXxV1ABl5LbakNExNmZIg= github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf h1:CAKfRE2YtTUIjjh1bkBtyYFaUT/WmOqsJjgtihT0vMI= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -183,7 +184,6 @@ github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5Jflh github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M= github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -247,16 +247,17 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= @@ -266,7 +267,6 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -276,7 +276,6 @@ github.com/google/go-metrics-stackdriver v0.2.0 h1:rbs2sxHAPn2OtUj9JdR/Gij1YKGl0 github.com/google/go-metrics-stackdriver v0.2.0/go.mod h1:KLcPyp3dWJAFD+yHisGlJSZktIsTjb50eB72U2YZ9K0= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -300,7 +299,6 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c h1:Lh2aW+HnU2Nbe1gqD9SOJLJxW1jBMmQOktN2acDyJk8= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= @@ -320,11 +318,9 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul-template v0.22.0 h1:ti5cqAekOeMfFYLJCjlPtKGwBcqwVxoZO/Y2vctwuUE= github.com/hashicorp/consul-template v0.22.0/go.mod h1:lHrykBIcPobCuEcIMLJryKxDyk2lUMnQWmffOEONH0k= -github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.2.1-0.20200128105449-6681be918a6e h1:vOqdnsq53winzJDN6RTQe9n9g87S595PNsdwKyBWXRM= github.com/hashicorp/consul/api v1.2.1-0.20200128105449-6681be918a6e/go.mod h1:ztzLK20HA5O27oTf2j/wbNgq8qj/crN8xsSx7pzX0sc= -github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.2.0 h1:GWFYFmry/k4b1hEoy7kSkmU8e30GAyI4VZHk0fRxeL4= github.com/hashicorp/consul/sdk v0.2.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -335,7 +331,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-gatedio v0.5.0 h1:Jm1X5yP4yCqqWj5L1TgW7iZwCVPGtVc+mro5r/XX7Tg= github.com/hashicorp/go-gatedio v0.5.0/go.mod h1:Lr3t8L6IyxD3DAeaUxGcgl2JnRUpWMCsmBl4Omu/2t4= -github.com/hashicorp/go-gcp-common v0.5.0 h1:kkIQTjNTopn4eXQ1+lCiHYZXUtgIZvbc6YtAQkMnTos= github.com/hashicorp/go-gcp-common v0.5.0/go.mod h1:IDGUI2N/OS3PiU4qZcXJeWKPI6O/9Y8hOrbSiMcqyYw= github.com/hashicorp/go-gcp-common v0.6.0 h1:m1X+DK003bj4WEjqOnv+Csepb3zpfN/bidboUeUSj68= github.com/hashicorp/go-gcp-common v0.6.0/go.mod h1:RuZi18562/z30wxOzpjeRrGcmk9Ro/rBzixaSZDhIhY= @@ -343,15 +338,14 @@ github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9 github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.10.1 h1:uyt/l0dWjJ879yiAu+T7FG3/6QX+zwm4bQ8P7XsYt3o= -github.com/hashicorp/go-hclog v0.10.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.12.1 h1:99niEVkDqsEv3/jINwoOUgGE9L41LHXM4k3jTkV+DdA= +github.com/hashicorp/go-hclog v0.12.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-kms-wrapping v0.5.1 h1:Ed6Z5gV3LY3J9Ora4cwxVmV8Hyt6CPOTrQoGIPry2Ew= -github.com/hashicorp/go-kms-wrapping v0.5.1/go.mod h1:cGIibZmMx9qlxS1pZTUrEgGqA+7u3zJyvVYMhjU2bDs= +github.com/hashicorp/go-kms-wrapping v0.5.5 h1:ld350yu4UPAFCyt5NifPU3WpFts71z69n3NfMeTv2z8= +github.com/hashicorp/go-kms-wrapping v0.5.5/go.mod h1:FeTpMJSbqrCtAeEK30hlNS8jm6W7cjzmLWurZ4Tk/J4= github.com/hashicorp/go-kms-wrapping/entropy v0.1.0 h1:xuTi5ZwjimfpvpL09jDE71smCBRpnF5xfo871BSX4gs= github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= github.com/hashicorp/go-memdb v1.0.2 h1:AIjzJlwIxz2inhZqRJZfe6D15lPeF0/cZyS1BVlnlHg= @@ -369,7 +363,6 @@ github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es github.com/hashicorp/go-retryablehttp v0.6.2 h1:bHM2aVXwBtBJWxHtkSrWuI4umABCUczs52eiUS9nSiw= github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -380,8 +373,6 @@ github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwM github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2-0.20191001231223-f32f5fe8d6a8 h1:PKbxRbsOP7R3f/TpdqcgXrO69T3yd9nLoR+RMRUxSxA= -github.com/hashicorp/go-uuid v1.0.2-0.20191001231223-f32f5fe8d6a8/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -450,14 +441,12 @@ github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2 h1:X9eK6NSb1qafvoE github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2/go.mod h1:YRW9zn9NZNitRlPYNAWRp/YEdKCF/X8aOg8IYSxFT5Y= github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2 h1:618nyNUHX2Oc7pcQh6r0Zm0kaMrhkfAyUyFmDFwyYnQ= github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2/go.mod h1:9Cy4Jp779BjuIOhYLjEfH3M3QCUxZgPnvJ3tAOOmof4= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4 h1:3K3KcD4S6/Y2hevi70EzUTNKOS3cryQyhUnkjE6Tz0w= github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= @@ -491,9 +480,7 @@ github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f h1:ENpDacvnr8fa github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -644,35 +631,27 @@ github.com/pquerna/otp v1.2.1-0.20191009055518-468c2dd2b58d h1:PinQItctnaL2LtkaS github.com/pquerna/otp v1.2.1-0.20191009055518-468c2dd2b58d/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -718,12 +697,11 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= @@ -739,8 +717,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -786,6 +764,7 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -816,7 +795,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -832,7 +810,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -859,7 +836,6 @@ golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= @@ -918,7 +894,6 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -926,7 +901,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -948,7 +922,6 @@ gopkg.in/ory-am/dockertest.v3 v3.3.4 h1:oen8RiwxVNxtQ1pRoV4e4jqh6UjNsOuIZ1NXns6j gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y= gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -956,7 +929,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= diff --git a/helper/builtinplugins/registry.go b/helper/builtinplugins/registry.go index d1591eaf7d..6148d2cd41 100644 --- a/helper/builtinplugins/registry.go +++ b/helper/builtinplugins/registry.go @@ -40,6 +40,7 @@ import ( logicalGcpKms "github.com/hashicorp/vault-plugin-secrets-gcpkms" logicalKv "github.com/hashicorp/vault-plugin-secrets-kv" logicalMongoAtlas "github.com/hashicorp/vault-plugin-secrets-mongodbatlas" + logicalOpenLDAP "github.com/hashicorp/vault-plugin-secrets-openldap" logicalAws "github.com/hashicorp/vault/builtin/logical/aws" logicalCass "github.com/hashicorp/vault/builtin/logical/cassandra" logicalConsul "github.com/hashicorp/vault/builtin/logical/consul" @@ -47,7 +48,6 @@ import ( logicalMssql "github.com/hashicorp/vault/builtin/logical/mssql" logicalMysql "github.com/hashicorp/vault/builtin/logical/mysql" logicalNomad "github.com/hashicorp/vault/builtin/logical/nomad" - logicalOpenLDAP "github.com/hashicorp/vault-plugin-secrets-openldap" logicalPki "github.com/hashicorp/vault/builtin/logical/pki" logicalPostgres "github.com/hashicorp/vault/builtin/logical/postgresql" logicalRabbit "github.com/hashicorp/vault/builtin/logical/rabbitmq" diff --git a/helper/testhelpers/seal/sealhelper.go b/helper/testhelpers/seal/sealhelper.go index 73425f9f23..3fa449e5a0 100644 --- a/helper/testhelpers/seal/sealhelper.go +++ b/helper/testhelpers/seal/sealhelper.go @@ -6,13 +6,13 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/builtin/logical/transit" - "github.com/hashicorp/vault/command/server/seal" "github.com/hashicorp/vault/helper/testhelpers/teststorage" "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/vault" - vaultseal "github.com/hashicorp/vault/vault/seal" + "github.com/hashicorp/vault/vault/seal" "github.com/mitchellh/go-testing-interface" ) @@ -65,12 +65,12 @@ func (tss *TransitSealServer) MakeSeal(t testing.T, key string) vault.Seal { "key_name": key, "tls_ca_cert": tss.CACertPEMFile, } - transitSeal, _, err := seal.GetTransitKMSFunc(nil, wrapperConfig) + transitSeal, _, err := configutil.GetTransitKMSFunc(nil, &configutil.KMS{Config: wrapperConfig}) if err != nil { t.Fatalf("error setting wrapper config: %v", err) } - return vault.NewAutoSeal(&vaultseal.Access{ + return vault.NewAutoSeal(&seal.Access{ Wrapper: transitSeal, }) } diff --git a/http/forwarded_for_test.go b/http/forwarded_for_test.go index 170b54334d..9323f5bf1c 100644 --- a/http/forwarded_for_test.go +++ b/http/forwarded_for_test.go @@ -7,9 +7,20 @@ import ( "testing" sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/vault" ) +func getListenerConfigForMarshalerTest(addr sockaddr.IPAddr) *configutil.Listener { + return &configutil.Listener{ + XForwardedForAuthorizedAddrs: []*sockaddr.SockAddrMarshaler{ + { + SockAddr: addr, + }, + }, + } +} + func TestHandler_XForwardedFor(t *testing.T) { goodAddr, err := sockaddr.NewIPAddr("127.0.0.1") if err != nil { @@ -29,11 +40,9 @@ func TestHandler_XForwardedFor(t *testing.T) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.RemoteAddr)) }) - return WrapForwardedForHandler(origHandler, []*sockaddr.SockAddrMarshaler{ - &sockaddr.SockAddrMarshaler{ - SockAddr: goodAddr, - }, - }, true, false, 0) + listenerConfig := getListenerConfigForMarshalerTest(goodAddr) + listenerConfig.XForwardedForRejectNotPresent = true + return WrapForwardedForHandler(origHandler, listenerConfig) } cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ @@ -74,11 +83,9 @@ func TestHandler_XForwardedFor(t *testing.T) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.RemoteAddr)) }) - return WrapForwardedForHandler(origHandler, []*sockaddr.SockAddrMarshaler{ - &sockaddr.SockAddrMarshaler{ - SockAddr: badAddr, - }, - }, true, false, 0) + listenerConfig := getListenerConfigForMarshalerTest(badAddr) + listenerConfig.XForwardedForRejectNotPresent = true + return WrapForwardedForHandler(origHandler, listenerConfig) } cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ @@ -111,11 +118,10 @@ func TestHandler_XForwardedFor(t *testing.T) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.RemoteAddr)) }) - return WrapForwardedForHandler(origHandler, []*sockaddr.SockAddrMarshaler{ - &sockaddr.SockAddrMarshaler{ - SockAddr: badAddr, - }, - }, true, true, 0) + listenerConfig := getListenerConfigForMarshalerTest(badAddr) + listenerConfig.XForwardedForRejectNotPresent = true + listenerConfig.XForwardedForRejectNotAuthorized = true + return WrapForwardedForHandler(origHandler, listenerConfig) } cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ @@ -145,11 +151,11 @@ func TestHandler_XForwardedFor(t *testing.T) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.RemoteAddr)) }) - return WrapForwardedForHandler(origHandler, []*sockaddr.SockAddrMarshaler{ - &sockaddr.SockAddrMarshaler{ - SockAddr: goodAddr, - }, - }, true, true, 4) + listenerConfig := getListenerConfigForMarshalerTest(goodAddr) + listenerConfig.XForwardedForRejectNotPresent = true + listenerConfig.XForwardedForRejectNotAuthorized = true + listenerConfig.XForwardedForHopSkips = 4 + return WrapForwardedForHandler(origHandler, listenerConfig) } cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ @@ -179,11 +185,11 @@ func TestHandler_XForwardedFor(t *testing.T) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.RemoteAddr)) }) - return WrapForwardedForHandler(origHandler, []*sockaddr.SockAddrMarshaler{ - &sockaddr.SockAddrMarshaler{ - SockAddr: goodAddr, - }, - }, true, true, 1) + listenerConfig := getListenerConfigForMarshalerTest(goodAddr) + listenerConfig.XForwardedForRejectNotPresent = true + listenerConfig.XForwardedForRejectNotAuthorized = true + listenerConfig.XForwardedForHopSkips = 1 + return WrapForwardedForHandler(origHandler, listenerConfig) } cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ @@ -216,11 +222,11 @@ func TestHandler_XForwardedFor(t *testing.T) { w.WriteHeader(http.StatusOK) w.Write([]byte(r.RemoteAddr)) }) - return WrapForwardedForHandler(origHandler, []*sockaddr.SockAddrMarshaler{ - &sockaddr.SockAddrMarshaler{ - SockAddr: goodAddr, - }, - }, true, true, 1) + listenerConfig := getListenerConfigForMarshalerTest(goodAddr) + listenerConfig.XForwardedForRejectNotPresent = true + listenerConfig.XForwardedForRejectNotAuthorized = true + listenerConfig.XForwardedForHopSkips = 1 + return WrapForwardedForHandler(origHandler, listenerConfig) } cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{ diff --git a/http/handler.go b/http/handler.go index 513d72c03a..62517eb457 100644 --- a/http/handler.go +++ b/http/handler.go @@ -23,6 +23,7 @@ import ( cleanhttp "github.com/hashicorp/go-cleanhttp" sockaddr "github.com/hashicorp/go-sockaddr" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/helper/parseutil" @@ -161,7 +162,7 @@ func Handler(props *vault.HandlerProperties) http.Handler { } // Register metrics path without authentication if enabled - if props.UnauthenticatedMetricsAccess { + if props.ListenerConfig != nil && props.ListenerConfig.Telemetry.UnauthenticatedMetricsAccess { mux.Handle("/v1/sys/metrics", handleMetricsUnauthenticated(core)) } else { mux.Handle("/v1/sys/metrics", handleLogicalNoForward(core)) @@ -252,10 +253,19 @@ func handleAuditNonLogical(core *vault.Core, h http.Handler) http.Handler { // wrapGenericHandler wraps the handler with an extra layer of handler where // tasks that should be commonly handled for all the requests and/or responses // are performed. -func wrapGenericHandler(core *vault.Core, h http.Handler, maxRequestSize int64, maxRequestDuration time.Duration) http.Handler { +func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerProperties) http.Handler { + var maxRequestDuration time.Duration + var maxRequestSize int64 + if props.ListenerConfig != nil { + maxRequestDuration = props.ListenerConfig.MaxRequestDuration + maxRequestSize = props.ListenerConfig.MaxRequestSize + } if maxRequestDuration == 0 { maxRequestDuration = vault.DefaultMaxRequestDuration } + if maxRequestSize == 0 { + maxRequestSize = DefaultMaxRequestSize + } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Set the Cache-Control header for all the responses returned // by Vault @@ -296,7 +306,11 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, maxRequestSize int64, }) } -func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAddrMarshaler, rejectNotPresent, rejectNonAuthz bool, hopSkips int) http.Handler { +func WrapForwardedForHandler(h http.Handler, l *configutil.Listener) http.Handler { + rejectNotPresent := l.XForwardedForRejectNotPresent + hopSkips := l.XForwardedForHopSkips + authorizedAddrs := l.XForwardedForAuthorizedAddrs + rejectNotAuthz := l.XForwardedForRejectNotAuthorized return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { headers, headersOK := r.Header[textproto.CanonicalMIMEHeaderKey("X-Forwarded-For")] if !headersOK || len(headers) == 0 { @@ -342,7 +356,7 @@ func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAdd if !found { // If we didn't find it and aren't configured to reject, simply // don't trust it - if !rejectNonAuthz { + if !rejectNotAuthz { h.ServeHTTP(w, r) return } @@ -362,7 +376,7 @@ func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAdd } } - indexToUse := len(acc) - 1 - hopSkips + indexToUse := int64(len(acc)) - 1 - hopSkips if indexToUse < 0 { // This is likely an error in either configuration or other // infrastructure. We could either deny the request, or we diff --git a/http/handler_test.go b/http/handler_test.go index 96cee3b387..a409c699a1 100644 --- a/http/handler_test.go +++ b/http/handler_test.go @@ -655,7 +655,6 @@ func testNonPrintable(t *testing.T, disable bool) { ln, addr := TestListener(t) props := &vault.HandlerProperties{ Core: core, - MaxRequestSize: DefaultMaxRequestSize, DisablePrintableCheck: disable, } TestServerWithListenerAndProperties(t, ln, addr, core, props) diff --git a/http/logical_test.go b/http/logical_test.go index 8f836dc49b..550f5f782b 100644 --- a/http/logical_test.go +++ b/http/logical_test.go @@ -267,7 +267,9 @@ func TestLogical_RequestSizeLimit(t *testing.T) { defer ln.Close() TestServerAuth(t, addr, token) - // Write a very large object, should fail + // Write a very large object, should fail. This test works because Go will + // convert the byte slice to base64, which makes it significantly larger + // than the default max request size. resp := testHttpPut(t, token, addr+"/v1/secret/foo", map[string]interface{}{ "data": make([]byte, DefaultMaxRequestSize), }) diff --git a/http/sys_metrics_test.go b/http/sys_metrics_test.go index 5f93c55240..492e6514ba 100644 --- a/http/sys_metrics_test.go +++ b/http/sys_metrics_test.go @@ -6,6 +6,7 @@ import ( "github.com/armon/go-metrics" "github.com/hashicorp/vault/helper/metricsutil" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/vault" ) @@ -32,9 +33,12 @@ func TestSysMetricsUnauthenticated(t *testing.T) { // Setup new custom listener with unauthenticated metrics access ln, addr = TestListener(t) props := &vault.HandlerProperties{ - Core: core, - MaxRequestSize: DefaultMaxRequestSize, - UnauthenticatedMetricsAccess: true, + Core: core, + ListenerConfig: &configutil.Listener{ + Telemetry: configutil.ListenerTelemetry{ + UnauthenticatedMetricsAccess: true, + }, + }, } TestServerWithListenerAndProperties(t, ln, addr, core, props) defer ln.Close() diff --git a/http/testing.go b/http/testing.go index ebc2edd1b6..be9569dc96 100644 --- a/http/testing.go +++ b/http/testing.go @@ -44,8 +44,7 @@ func TestServerWithListener(tb testing.TB, ln net.Listener, addr string, core *v // Create a muxer to handle our requests so that we can authenticate // for tests. props := &vault.HandlerProperties{ - Core: core, - MaxRequestSize: DefaultMaxRequestSize, + Core: core, } TestServerWithListenerAndProperties(tb, ln, addr, core, props) } diff --git a/http/util.go b/http/util.go index ff50a4838b..c4bd282d84 100644 --- a/http/util.go +++ b/http/util.go @@ -15,7 +15,7 @@ var ( genericWrapping = func(core *vault.Core, in http.Handler, props *vault.HandlerProperties) http.Handler { // Wrap the help wrapped handler with another layer with a generic // handler - return wrapGenericHandler(core, in, props.MaxRequestSize, props.MaxRequestDuration) + return wrapGenericHandler(core, in, props) } additionalRoutes = func(mux *http.ServeMux, core *vault.Core) {} diff --git a/internalshared/configutil/config.go b/internalshared/configutil/config.go new file mode 100644 index 0000000000..f811b1ed1a --- /dev/null +++ b/internalshared/configutil/config.go @@ -0,0 +1,211 @@ +package configutil + +import ( + "fmt" + "io/ioutil" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/sdk/helper/parseutil" +) + +// SharedConfig contains some shared values +type SharedConfig struct { + EntSharedConfig + + Listeners []*Listener `hcl:"-"` + + Seals []*KMS `hcl:"-"` + Entropy *Entropy `hcl:"-"` + + DisableMlock bool `hcl:"-"` + DisableMlockRaw interface{} `hcl:"disable_mlock"` + + Telemetry *Telemetry `hcl:"telemetry"` + + DefaultMaxRequestDuration time.Duration `hcl:"-"` + DefaultMaxRequestDurationRaw interface{} `hcl:"default_max_request_duration"` + + // LogFormat specifies the log format. Valid values are "standard" and + // "json". The values are case-insenstive. If no log format is specified, + // then standard format will be used. + LogFormat string `hcl:"log_format"` + LogLevel string `hcl:"log_level"` + + PidFile string `hcl:"pid_file"` + + ClusterName string `hcl:"cluster_name"` +} + +// LoadConfigFile loads the configuration from the given file. +func LoadConfigFile(path string) (*SharedConfig, error) { + // Read the file + d, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + return ParseConfig(string(d)) +} + +func ParseConfig(d string) (*SharedConfig, error) { + // Parse! + obj, err := hcl.Parse(d) + if err != nil { + return nil, err + } + + // Start building the result + var result SharedConfig + if err := hcl.DecodeObject(&result, obj); err != nil { + return nil, err + } + + if result.DefaultMaxRequestDurationRaw != nil { + if result.DefaultMaxRequestDuration, err = parseutil.ParseDurationSecond(result.DefaultMaxRequestDurationRaw); err != nil { + return nil, err + } + result.DefaultMaxRequestDurationRaw = nil + } + + if result.DisableMlockRaw != nil { + if result.DisableMlock, err = parseutil.ParseBool(result.DisableMlockRaw); err != nil { + return nil, err + } + result.DisableMlockRaw = nil + } + + list, ok := obj.Node.(*ast.ObjectList) + if !ok { + return nil, fmt.Errorf("error parsing: file doesn't contain a root object") + } + + if o := list.Filter("hsm"); len(o.Items) > 0 { + if err := parseKMS(&result, o, "hsm", 1); err != nil { + return nil, errwrap.Wrapf("error parsing 'hsm': {{err}}", err) + } + } + + if o := list.Filter("seal"); len(o.Items) > 0 { + if err := parseKMS(&result, o, "seal", 2); err != nil { + return nil, errwrap.Wrapf("error parsing 'seal': {{err}}", err) + } + } + + if o := list.Filter("kms"); len(o.Items) > 0 { + if err := parseKMS(&result, o, "kms", 2); err != nil { + return nil, errwrap.Wrapf("error parsing 'kms': {{err}}", err) + } + } + + if o := list.Filter("entropy"); len(o.Items) > 0 { + if err := ParseEntropy(&result, o, "entropy"); err != nil { + return nil, errwrap.Wrapf("error parsing 'entropy': {{err}}", err) + } + } + + if o := list.Filter("listener"); len(o.Items) > 0 { + if err := ParseListeners(&result, o); err != nil { + return nil, errwrap.Wrapf("error parsing 'listener': {{err}}", err) + } + } + + if o := list.Filter("telemetry"); len(o.Items) > 0 { + if err := parseTelemetry(&result, o); err != nil { + return nil, errwrap.Wrapf("error parsing 'telemetry': {{err}}", err) + } + } + + entConfig := &(result.EntSharedConfig) + if err := entConfig.ParseConfig(list); err != nil { + return nil, errwrap.Wrapf("error parsing enterprise config: {{err}}", err) + } + + return &result, nil +} + +// Sanitized returns a copy of the config with all values that are considered +// sensitive stripped. It also strips all `*Raw` values that are mainly +// used for parsing. +// +// Specifically, the fields that this method strips are: +// - KMS.Config +// - Telemetry.CirconusAPIToken +func (c *SharedConfig) Sanitized() map[string]interface{} { + if c == nil { + return nil + } + + result := map[string]interface{}{ + "disable_mlock": c.DisableMlock, + + "default_max_request_duration": c.DefaultMaxRequestDuration, + + "log_level": c.LogLevel, + "log_format": c.LogFormat, + + "pid_file": c.PidFile, + + "cluster_name": c.ClusterName, + } + + // Sanitize listeners + if len(c.Listeners) != 0 { + var sanitizedListeners []interface{} + for _, ln := range c.Listeners { + cleanLn := map[string]interface{}{ + "type": ln.Type, + "config": ln.RawConfig, + } + sanitizedListeners = append(sanitizedListeners, cleanLn) + } + result["listeners"] = sanitizedListeners + } + + // Sanitize seals stanza + if len(c.Seals) != 0 { + var sanitizedSeals []interface{} + for _, s := range c.Seals { + cleanSeal := map[string]interface{}{ + "type": s.Type, + "disabled": s.Disabled, + } + sanitizedSeals = append(sanitizedSeals, cleanSeal) + } + result["seals"] = sanitizedSeals + } + + // Sanitize telemetry stanza + if c.Telemetry != nil { + sanitizedTelemetry := map[string]interface{}{ + "statsite_address": c.Telemetry.StatsiteAddr, + "statsd_address": c.Telemetry.StatsdAddr, + "disable_hostname": c.Telemetry.DisableHostname, + "metrics_prefix": c.Telemetry.MetricsPrefix, + "circonus_api_token": "", + "circonus_api_app": c.Telemetry.CirconusAPIApp, + "circonus_api_url": c.Telemetry.CirconusAPIURL, + "circonus_submission_interval": c.Telemetry.CirconusSubmissionInterval, + "circonus_submission_url": c.Telemetry.CirconusCheckSubmissionURL, + "circonus_check_id": c.Telemetry.CirconusCheckID, + "circonus_check_force_metric_activation": c.Telemetry.CirconusCheckForceMetricActivation, + "circonus_check_instance_id": c.Telemetry.CirconusCheckInstanceID, + "circonus_check_search_tag": c.Telemetry.CirconusCheckSearchTag, + "circonus_check_tags": c.Telemetry.CirconusCheckTags, + "circonus_check_display_name": c.Telemetry.CirconusCheckDisplayName, + "circonus_broker_id": c.Telemetry.CirconusBrokerID, + "circonus_broker_select_tag": c.Telemetry.CirconusBrokerSelectTag, + "dogstatsd_addr": c.Telemetry.DogStatsDAddr, + "dogstatsd_tags": c.Telemetry.DogStatsDTags, + "prometheus_retention_time": c.Telemetry.PrometheusRetentionTime, + "stackdriver_project_id": c.Telemetry.StackdriverProjectID, + "stackdriver_location": c.Telemetry.StackdriverLocation, + "stackdriver_namespace": c.Telemetry.StackdriverNamespace, + "stackdriver_debug_logs": c.Telemetry.StackdriverDebugLogs, + } + result["telemetry"] = sanitizedTelemetry + } + + return result +} diff --git a/internalshared/configutil/config_util.go b/internalshared/configutil/config_util.go new file mode 100644 index 0000000000..e9c7d5d549 --- /dev/null +++ b/internalshared/configutil/config_util.go @@ -0,0 +1,18 @@ +// +build !enterprise + +package configutil + +import ( + "github.com/hashicorp/hcl/hcl/ast" +) + +type EntSharedConfig struct { +} + +func (ec *EntSharedConfig) ParseConfig(list *ast.ObjectList) error { + return nil +} + +func ParseEntropy(result *SharedConfig, list *ast.ObjectList, blockName string) error { + return nil +} diff --git a/internalshared/configutil/kms.go b/internalshared/configutil/kms.go new file mode 100644 index 0000000000..dc7d145113 --- /dev/null +++ b/internalshared/configutil/kms.go @@ -0,0 +1,313 @@ +// +build !enterprise + +package configutil + +import ( + "crypto/rand" + "fmt" + "io" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-hclog" + wrapping "github.com/hashicorp/go-kms-wrapping" + aeadwrapper "github.com/hashicorp/go-kms-wrapping/wrappers/aead" + "github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms" + "github.com/hashicorp/go-kms-wrapping/wrappers/awskms" + "github.com/hashicorp/go-kms-wrapping/wrappers/azurekeyvault" + "github.com/hashicorp/go-kms-wrapping/wrappers/gcpckms" + "github.com/hashicorp/go-kms-wrapping/wrappers/ocikms" + "github.com/hashicorp/go-kms-wrapping/wrappers/transit" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/sdk/helper/parseutil" + "github.com/hashicorp/vault/sdk/logical" +) + +var ( + ConfigureWrapper = configureWrapper + CreateSecureRandomReaderFunc = createSecureRandomReader +) + +// Entropy contains Entropy configuration for the server +type EntropyMode int + +const ( + EntropyUnknown EntropyMode = iota + EntropyAugmentation +) + +type Entropy struct { + Mode EntropyMode +} + +// KMS contains KMS configuration for the server +type KMS struct { + Type string + // Purpose can be used to allow a string-based specification of what this + // KMS is designated for, in situations where we want to allow more than + // one KMS to be specified + Purpose []string `hcl:"-"` + + Disabled bool + Config map[string]string +} + +func (k *KMS) GoString() string { + return fmt.Sprintf("*%#v", *k) +} + +func parseKMS(result *SharedConfig, list *ast.ObjectList, blockName string, maxKMS int) error { + if len(list.Items) > maxKMS { + return fmt.Errorf("only two or less %q blocks are permitted", blockName) + } + + seals := make([]*KMS, 0, len(list.Items)) + for _, item := range list.Items { + key := blockName + if len(item.Keys) > 0 { + key = item.Keys[0].Token.Value().(string) + } + + // We first decode into a map[string]interface{} because purpose isn't + // necessarily a string. Then we migrate everything else over to + // map[string]string and error if it doesn't work. + var m map[string]interface{} + if err := hcl.DecodeObject(&m, item.Val); err != nil { + return multierror.Prefix(err, fmt.Sprintf("%s.%s:", blockName, key)) + } + + var purpose []string + var err error + if v, ok := m["purpose"]; ok { + if purpose, err = parseutil.ParseCommaStringSlice(v); err != nil { + return multierror.Prefix(fmt.Errorf("unable to parse 'purpose' in kms type %q: %w", key, err), fmt.Sprintf("%s.%s:", blockName, key)) + } + for i, p := range purpose { + purpose[i] = strings.ToLower(p) + } + delete(m, "purpose") + } + + var disabled bool + if v, ok := m["disabled"]; ok { + disabled, err = parseutil.ParseBool(v) + if err != nil { + return multierror.Prefix(err, fmt.Sprintf("%s.%s:", blockName, key)) + } + delete(m, "disabled") + } + + strMap := make(map[string]string, len(m)) + for k, v := range m { + if vs, ok := v.(string); ok { + strMap[k] = vs + } else { + return multierror.Prefix(fmt.Errorf("unable to parse 'purpose' in kms type %q: value could not be parsed as string", key), fmt.Sprintf("%s.%s:", blockName, key)) + } + } + + seal := &KMS{ + Type: strings.ToLower(key), + Purpose: purpose, + Disabled: disabled, + } + if len(strMap) > 0 { + seal.Config = strMap + } + seals = append(seals, seal) + } + + result.Seals = append(result.Seals, seals...) + + return nil +} + +func configureWrapper(configKMS *KMS, infoKeys *[]string, info *map[string]string, logger hclog.Logger) (wrapping.Wrapper, error) { + var wrapper wrapping.Wrapper + var kmsInfo map[string]string + var err error + + opts := &wrapping.WrapperOptions{ + Logger: logger, + } + + switch configKMS.Type { + case wrapping.Shamir: + return nil, nil + + case wrapping.AEAD: + wrapper, kmsInfo, err = GetAEADKMSFunc(opts, configKMS) + + case wrapping.AliCloudKMS: + wrapper, kmsInfo, err = GetAliCloudKMSFunc(opts, configKMS) + + case wrapping.AWSKMS: + wrapper, kmsInfo, err = GetAWSKMSFunc(opts, configKMS) + + case wrapping.AzureKeyVault: + wrapper, kmsInfo, err = GetAzureKeyVaultKMSFunc(opts, configKMS) + + case wrapping.GCPCKMS: + wrapper, kmsInfo, err = GetGCPCKMSKMSFunc(opts, configKMS) + + case wrapping.OCIKMS: + wrapper, kmsInfo, err = GetOCIKMSKMSFunc(opts, configKMS) + + case wrapping.Transit: + wrapper, kmsInfo, err = GetTransitKMSFunc(opts, configKMS) + + case wrapping.PKCS11: + return nil, fmt.Errorf("KMS type 'pkcs11' requires the Vault Enterprise HSM binary") + + default: + return nil, fmt.Errorf("Unknown KMS type %q", configKMS.Type) + } + + if err != nil { + return nil, err + } + + for k, v := range kmsInfo { + *infoKeys = append(*infoKeys, k) + (*info)[k] = v + } + + return wrapper, nil +} + +func GetAEADKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := aeadwrapper.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + return nil, nil, err + } + info := make(map[string]string) + if wrapperInfo != nil { + str := "AEAD Type" + if len(kms.Purpose) > 0 { + str = fmt.Sprintf("%v %s", kms.Purpose, str) + } + info[str] = wrapperInfo["aead_type"] + } + return wrapper, info, nil +} + +func GetAliCloudKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := alicloudkms.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + // If the error is any other than logical.KeyNotFoundError, return the error + if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { + return nil, nil, err + } + } + info := make(map[string]string) + if wrapperInfo != nil { + info["AliCloud KMS Region"] = wrapperInfo["region"] + info["AliCloud KMS KeyID"] = wrapperInfo["kms_key_id"] + if domain, ok := wrapperInfo["domain"]; ok { + info["AliCloud KMS Domain"] = domain + } + } + return wrapper, info, nil +} + +func GetAWSKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := awskms.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + // If the error is any other than logical.KeyNotFoundError, return the error + if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { + return nil, nil, err + } + } + info := make(map[string]string) + if wrapperInfo != nil { + info["AWS KMS Region"] = wrapperInfo["region"] + info["AWS KMS KeyID"] = wrapperInfo["kms_key_id"] + if endpoint, ok := wrapperInfo["endpoint"]; ok { + info["AWS KMS Endpoint"] = endpoint + } + } + return wrapper, info, nil +} + +func GetAzureKeyVaultKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := azurekeyvault.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + // If the error is any other than logical.KeyNotFoundError, return the error + if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { + return nil, nil, err + } + } + info := make(map[string]string) + if wrapperInfo != nil { + info["Azure Environment"] = wrapperInfo["environment"] + info["Azure Vault Name"] = wrapperInfo["vault_name"] + info["Azure Key Name"] = wrapperInfo["key_name"] + } + return wrapper, info, nil +} + +func GetGCPCKMSKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := gcpckms.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + // If the error is any other than logical.KeyNotFoundError, return the error + if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { + return nil, nil, err + } + } + info := make(map[string]string) + if wrapperInfo != nil { + info["GCP KMS Project"] = wrapperInfo["project"] + info["GCP KMS Region"] = wrapperInfo["region"] + info["GCP KMS Key Ring"] = wrapperInfo["key_ring"] + info["GCP KMS Crypto Key"] = wrapperInfo["crypto_key"] + } + return wrapper, info, nil +} + +func GetOCIKMSKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := ocikms.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + return nil, nil, err + } + info := make(map[string]string) + if wrapperInfo != nil { + info["OCI KMS KeyID"] = wrapperInfo[ocikms.KMSConfigKeyID] + info["OCI KMS Crypto Endpoint"] = wrapperInfo[ocikms.KMSConfigCryptoEndpoint] + info["OCI KMS Management Endpoint"] = wrapperInfo[ocikms.KMSConfigManagementEndpoint] + info["OCI KMS Principal Type"] = wrapperInfo["principal_type"] + } + return wrapper, info, nil +} + +func GetTransitKMSFunc(opts *wrapping.WrapperOptions, kms *KMS) (wrapping.Wrapper, map[string]string, error) { + wrapper := transit.NewWrapper(opts) + wrapperInfo, err := wrapper.SetConfig(kms.Config) + if err != nil { + // If the error is any other than logical.KeyNotFoundError, return the error + if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) { + return nil, nil, err + } + } + info := make(map[string]string) + if wrapperInfo != nil { + info["Transit Address"] = wrapperInfo["address"] + info["Transit Mount Path"] = wrapperInfo["mount_path"] + info["Transit Key Name"] = wrapperInfo["key_name"] + if namespace, ok := wrapperInfo["namespace"]; ok { + info["Transit Namespace"] = namespace + } + } + return wrapper, info, nil +} + +func createSecureRandomReader(conf *SharedConfig, wrapper wrapping.Wrapper) (io.Reader, error) { + return rand.Reader, nil +} diff --git a/internalshared/configutil/listener.go b/internalshared/configutil/listener.go new file mode 100644 index 0000000000..7e08ba3d0e --- /dev/null +++ b/internalshared/configutil/listener.go @@ -0,0 +1,315 @@ +package configutil + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/sdk/helper/parseutil" + "github.com/hashicorp/vault/sdk/helper/tlsutil" +) + +type ListenerTelemetry struct { + UnauthenticatedMetricsAccess bool `hcl:"-"` + UnauthenticatedMetricsAccessRaw interface{} `hcl:"unauthenticated_metrics_access"` +} + +// Listener is the listener configuration for the server. +type Listener struct { + RawConfig map[string]interface{} + + Type string + Purpose []string `hcl:"-"` + PurposeRaw interface{} `hcl:"purpose"` + + Address string `hcl:"address"` + ClusterAddress string `hcl:"cluster_address"` + MaxRequestSize int64 `hcl:"-"` + MaxRequestSizeRaw interface{} `hcl:"max_request_size"` + MaxRequestDuration time.Duration `hcl:"-"` + MaxRequestDurationRaw interface{} `hcl:"max_request_duration"` + RequireRequestHeader bool `hcl:"-"` + RequireRequestHeaderRaw interface{} `hcl:"require_request_header"` + + TLSDisable bool `hcl:"-"` + TLSDisableRaw interface{} `hcl:"tls_disable"` + TLSCertFile string `hcl:"tls_cert_file"` + TLSKeyFile string `hcl:"tls_key_file"` + TLSMinVersion string `hcl:"tls_min_version"` + TLSCipherSuites []uint16 `hcl:"-"` + TLSCipherSuitesRaw string `hcl:"tls_cipher_suites"` + TLSPreferServerCipherSuites bool `hcl:"-"` + TLSPreferServerCipherSuitesRaw interface{} `hcl:"tls_prefer_server_cipher_suites"` + TLSRequireAndVerifyClientCert bool `hcl:"-"` + TLSRequireAndVerifyClientCertRaw interface{} `hcl:"tls_require_and_verify_client_cert"` + TLSClientCAFile string `hcl:"tls_client_ca_file"` + TLSDisableClientCerts bool `hcl:"-"` + TLSDisableClientCertsRaw interface{} `hcl:"tls_disable_client_certs"` + + HTTPReadTimeout time.Duration `hcl:"-"` + HTTPReadTimeoutRaw interface{} `hcl:"http_read_timeout"` + HTTPReadHeaderTimeout time.Duration `hcl:"-"` + HTTPReadHeaderTimeoutRaw interface{} `hcl:"http_read_header_timeout"` + HTTPWriteTimeout time.Duration `hcl:"-"` + HTTPWriteTimeoutRaw interface{} `hcl:"http_write_timeout"` + HTTPIdleTimeout time.Duration `hcl:"-"` + HTTPIdleTimeoutRaw interface{} `hcl:"http_idle_timeout"` + + ProxyProtocolBehavior string `hcl:"proxy_protocol_behavior"` + ProxyProtocolAuthorizedAddrs []*sockaddr.SockAddrMarshaler `hcl:"-"` + ProxyProtocolAuthorizedAddrsRaw interface{} `hcl:"proxy_protocol_authorized_addrs"` + + XForwardedForAuthorizedAddrs []*sockaddr.SockAddrMarshaler `hcl:"-"` + XForwardedForAuthorizedAddrsRaw interface{} `hcl:"x_forwarded_for_authorized_addrs"` + XForwardedForHopSkips int64 `hcl:"-"` + XForwardedForHopSkipsRaw interface{} `hcl:"x_forwarded_for_hop_skips"` + XForwardedForRejectNotPresent bool `hcl:"-"` + XForwardedForRejectNotPresentRaw interface{} `hcl:"x_forwarded_for_reject_not_present"` + XForwardedForRejectNotAuthorized bool `hcl:"-"` + XForwardedForRejectNotAuthorizedRaw interface{} `hcl:"x_forwarded_for_reject_not_authorized"` + + SocketMode string `hcl:"socket_mode"` + SocketUser string `hcl:"socket_user"` + SocketGroup string `hcl:"socket_group"` + + Telemetry ListenerTelemetry `hcl:"telemetry"` + + // RandomPort is used only for some testing purposes + RandomPort bool `hcl:"-"` +} + +func (l *Listener) GoString() string { + return fmt.Sprintf("*%#v", *l) +} + +func ParseListeners(result *SharedConfig, list *ast.ObjectList) error { + var err error + result.Listeners = make([]*Listener, 0, len(list.Items)) + for i, item := range list.Items { + var l Listener + if err := hcl.DecodeObject(&l, item.Val); err != nil { + return multierror.Prefix(err, fmt.Sprintf("listeners.%d:", i)) + } + + // Hacky way, for now, to get the values we want for sanitizing + var m map[string]interface{} + if err := hcl.DecodeObject(&m, item.Val); err != nil { + return multierror.Prefix(err, fmt.Sprintf("listeners.%d:", i)) + } + l.RawConfig = m + + // Base values + { + switch { + case l.Type != "": + case len(item.Keys) == 1: + l.Type = strings.ToLower(item.Keys[0].Token.Value().(string)) + default: + return multierror.Prefix(errors.New("listener type must be specified"), fmt.Sprintf("listeners.%d:", i)) + } + + l.Type = strings.ToLower(l.Type) + switch l.Type { + case "tcp", "unix": + default: + return multierror.Prefix(fmt.Errorf("unsupported listener type %q", l.Type), fmt.Sprintf("listeners.%d:", i)) + } + + if l.PurposeRaw != nil { + if l.Purpose, err = parseutil.ParseCommaStringSlice(l.PurposeRaw); err != nil { + return multierror.Prefix(fmt.Errorf("unable to parse 'purpose' in listener type %q: %w", l.Type, err), fmt.Sprintf("listeners.%d:", i)) + } + for i, v := range l.Purpose { + l.Purpose[i] = strings.ToLower(v) + } + } + } + + // Request Parameters + { + if l.MaxRequestSizeRaw != nil { + if l.MaxRequestSize, err = parseutil.ParseInt(l.MaxRequestSizeRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing max_request_size: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + if l.MaxRequestSize < 0 { + return multierror.Prefix(errors.New("max_request_size cannot be negative"), fmt.Sprintf("listeners.%d", i)) + } + + l.MaxRequestSizeRaw = nil + } + + if l.MaxRequestDurationRaw != nil { + if l.MaxRequestDuration, err = parseutil.ParseDurationSecond(l.MaxRequestDurationRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing max_request_duration: %w", err), fmt.Sprintf("listeners.%d", i)) + } + if l.MaxRequestDuration < 0 { + return multierror.Prefix(errors.New("max_request_duration cannot be negative"), fmt.Sprintf("listeners.%d", i)) + } + + l.MaxRequestDurationRaw = nil + } + + if l.RequireRequestHeaderRaw != nil { + if l.RequireRequestHeader, err = parseutil.ParseBool(l.RequireRequestHeaderRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for require_request_header: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.RequireRequestHeaderRaw = nil + } + } + + // TLS Parameters + { + if l.TLSDisableRaw != nil { + if l.TLSDisable, err = parseutil.ParseBool(l.TLSDisableRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for tls_disable: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.TLSDisableRaw = nil + } + + if l.TLSCipherSuitesRaw != "" { + if l.TLSCipherSuites, err = tlsutil.ParseCiphers(l.TLSCipherSuitesRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for tls_cipher_suites: %w", err), fmt.Sprintf("listeners.%d", i)) + } + } + + if l.TLSPreferServerCipherSuitesRaw != nil { + if l.TLSPreferServerCipherSuites, err = parseutil.ParseBool(l.TLSPreferServerCipherSuitesRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for tls_prefer_server_cipher_suites: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.TLSPreferServerCipherSuitesRaw = nil + } + + if l.TLSRequireAndVerifyClientCertRaw != nil { + if l.TLSRequireAndVerifyClientCert, err = parseutil.ParseBool(l.TLSRequireAndVerifyClientCertRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for tls_require_and_verify_client_cert: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.TLSRequireAndVerifyClientCertRaw = nil + } + + if l.TLSDisableClientCertsRaw != nil { + if l.TLSDisableClientCerts, err = parseutil.ParseBool(l.TLSDisableClientCertsRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for tls_disable_client_certs: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.TLSDisableClientCertsRaw = nil + } + } + + // HTTP timeouts + { + if l.HTTPReadTimeoutRaw != nil { + if l.HTTPReadTimeout, err = parseutil.ParseDurationSecond(l.HTTPReadTimeoutRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing http_read_timeout: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.HTTPReadTimeoutRaw = nil + } + + if l.HTTPReadHeaderTimeoutRaw != nil { + if l.HTTPReadHeaderTimeout, err = parseutil.ParseDurationSecond(l.HTTPReadHeaderTimeoutRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing http_read_header_timeout: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.HTTPReadHeaderTimeoutRaw = nil + } + + if l.HTTPWriteTimeoutRaw != nil { + if l.HTTPWriteTimeout, err = parseutil.ParseDurationSecond(l.HTTPWriteTimeoutRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing http_write_timeout: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.HTTPWriteTimeoutRaw = nil + } + + if l.HTTPIdleTimeoutRaw != nil { + if l.HTTPIdleTimeout, err = parseutil.ParseDurationSecond(l.HTTPIdleTimeoutRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing http_idle_timeout: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.HTTPIdleTimeoutRaw = nil + } + } + + // Proxy Protocol config + { + if l.ProxyProtocolAuthorizedAddrsRaw != nil { + if l.ProxyProtocolAuthorizedAddrs, err = parseutil.ParseAddrs(l.ProxyProtocolAuthorizedAddrsRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing proxy_protocol_authorized_addrs: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + switch l.ProxyProtocolBehavior { + case "allow_authorized", "deny_authorized": + if len(l.ProxyProtocolAuthorizedAddrs) == 0 { + return multierror.Prefix(errors.New("proxy_protocol_behavior set to allow or deny only authorized addresses but no proxy_protocol_authorized_addrs value"), fmt.Sprintf("listeners.%d", i)) + } + } + + l.ProxyProtocolAuthorizedAddrsRaw = nil + } + } + + // X-Forwarded-For config + { + if l.XForwardedForAuthorizedAddrsRaw != nil { + if l.XForwardedForAuthorizedAddrs, err = parseutil.ParseAddrs(l.XForwardedForAuthorizedAddrsRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing x_forwarded_for_authorized_addrs: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.XForwardedForAuthorizedAddrsRaw = nil + } + + if l.XForwardedForHopSkipsRaw != nil { + if l.XForwardedForHopSkips, err = parseutil.ParseInt(l.XForwardedForHopSkipsRaw); err != nil { + return multierror.Prefix(fmt.Errorf("error parsing x_forwarded_for_hop_skips: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + if l.XForwardedForHopSkips < 0 { + return multierror.Prefix(fmt.Errorf("x_forwarded_for_hop_skips cannot be negative but set to %d", l.XForwardedForHopSkips), fmt.Sprintf("listeners.%d", i)) + } + + l.XForwardedForHopSkipsRaw = nil + } + + if l.XForwardedForRejectNotAuthorizedRaw != nil { + if l.XForwardedForRejectNotAuthorized, err = parseutil.ParseBool(l.XForwardedForRejectNotAuthorizedRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for x_forwarded_for_reject_not_authorized: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.XForwardedForRejectNotAuthorizedRaw = nil + } + + if l.XForwardedForRejectNotPresentRaw != nil { + if l.XForwardedForRejectNotPresent, err = parseutil.ParseBool(l.XForwardedForRejectNotPresentRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for x_forwarded_for_reject_not_present: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.XForwardedForRejectNotPresentRaw = nil + } + } + + // Telemetry + { + if l.Telemetry.UnauthenticatedMetricsAccessRaw != nil { + if l.Telemetry.UnauthenticatedMetricsAccess, err = parseutil.ParseBool(l.Telemetry.UnauthenticatedMetricsAccessRaw); err != nil { + return multierror.Prefix(fmt.Errorf("invalid value for telemetry.unauthenticated_metrics_access: %w", err), fmt.Sprintf("listeners.%d", i)) + } + + l.Telemetry.UnauthenticatedMetricsAccessRaw = nil + } + } + + result.Listeners = append(result.Listeners, &l) + } + + return nil +} diff --git a/internalshared/configutil/merge.go b/internalshared/configutil/merge.go new file mode 100644 index 0000000000..51f6fee887 --- /dev/null +++ b/internalshared/configutil/merge.go @@ -0,0 +1,65 @@ +package configutil + +func (c *SharedConfig) Merge(c2 *SharedConfig) *SharedConfig { + if c2 == nil { + return c + } + + result := new(SharedConfig) + + for _, l := range c.Listeners { + result.Listeners = append(result.Listeners, l) + } + for _, l := range c2.Listeners { + result.Listeners = append(result.Listeners, l) + } + + result.Entropy = c.Entropy + if c2.Entropy != nil { + result.Entropy = c2.Entropy + } + + for _, s := range c.Seals { + result.Seals = append(result.Seals, s) + } + for _, s := range c2.Seals { + result.Seals = append(result.Seals, s) + } + + result.Telemetry = c.Telemetry + if c2.Telemetry != nil { + result.Telemetry = c2.Telemetry + } + + result.DisableMlock = c.DisableMlock + if c2.DisableMlock { + result.DisableMlock = c2.DisableMlock + } + + result.DefaultMaxRequestDuration = c.DefaultMaxRequestDuration + if c2.DefaultMaxRequestDuration > result.DefaultMaxRequestDuration { + result.DefaultMaxRequestDuration = c2.DefaultMaxRequestDuration + } + + result.LogLevel = c.LogLevel + if c2.LogLevel != "" { + result.LogLevel = c2.LogLevel + } + + result.LogFormat = c.LogFormat + if c2.LogFormat != "" { + result.LogFormat = c2.LogFormat + } + + result.PidFile = c.PidFile + if c2.PidFile != "" { + result.PidFile = c2.PidFile + } + + result.ClusterName = c.ClusterName + if c2.ClusterName != "" { + result.ClusterName = c2.ClusterName + } + + return result +} diff --git a/internalshared/configutil/telemetry.go b/internalshared/configutil/telemetry.go new file mode 100644 index 0000000000..0abfffad89 --- /dev/null +++ b/internalshared/configutil/telemetry.go @@ -0,0 +1,339 @@ +package configutil + +import ( + "context" + "errors" + "fmt" + "time" + + monitoring "cloud.google.com/go/monitoring/apiv3" + "github.com/armon/go-metrics" + "github.com/armon/go-metrics/circonus" + "github.com/armon/go-metrics/datadog" + "github.com/armon/go-metrics/prometheus" + stackdriver "github.com/google/go-metrics-stackdriver" + stackdrivervault "github.com/google/go-metrics-stackdriver/vault" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/hcl" + "github.com/hashicorp/hcl/hcl/ast" + "github.com/hashicorp/vault/helper/metricsutil" + "github.com/hashicorp/vault/sdk/helper/parseutil" + "github.com/mitchellh/cli" + "google.golang.org/api/option" +) + +const ( + PrometheusDefaultRetentionTime = 24 * time.Hour +) + +// Telemetry is the telemetry configuration for the server +type Telemetry struct { + StatsiteAddr string `hcl:"statsite_address"` + StatsdAddr string `hcl:"statsd_address"` + + DisableHostname bool `hcl:"disable_hostname"` + EnableHostnameLabel bool `hcl:"enable_hostname_label"` + MetricsPrefix string `hcl:"metrics_prefix"` + + // Circonus: see https://github.com/circonus-labs/circonus-gometrics + // for more details on the various configuration options. + // Valid configuration combinations: + // - CirconusAPIToken + // metric management enabled (search for existing check or create a new one) + // - CirconusSubmissionUrl + // metric management disabled (use check with specified submission_url, + // broker must be using a public SSL certificate) + // - CirconusAPIToken + CirconusCheckSubmissionURL + // metric management enabled (use check with specified submission_url) + // - CirconusAPIToken + CirconusCheckID + // metric management enabled (use check with specified id) + + // CirconusAPIToken is a valid API Token used to create/manage check. If provided, + // metric management is enabled. + // Default: none + CirconusAPIToken string `hcl:"circonus_api_token"` + // CirconusAPIApp is an app name associated with API token. + // Default: "consul" + CirconusAPIApp string `hcl:"circonus_api_app"` + // CirconusAPIURL is the base URL to use for contacting the Circonus API. + // Default: "https://api.circonus.com/v2" + CirconusAPIURL string `hcl:"circonus_api_url"` + // CirconusSubmissionInterval is the interval at which metrics are submitted to Circonus. + // Default: 10s + CirconusSubmissionInterval string `hcl:"circonus_submission_interval"` + // CirconusCheckSubmissionURL is the check.config.submission_url field from a + // previously created HTTPTRAP check. + // Default: none + CirconusCheckSubmissionURL string `hcl:"circonus_submission_url"` + // CirconusCheckID is the check id (not check bundle id) from a previously created + // HTTPTRAP check. The numeric portion of the check._cid field. + // Default: none + CirconusCheckID string `hcl:"circonus_check_id"` + // CirconusCheckForceMetricActivation will force enabling metrics, as they are encountered, + // if the metric already exists and is NOT active. If check management is enabled, the default + // behavior is to add new metrics as they are encountered. If the metric already exists in the + // check, it will *NOT* be activated. This setting overrides that behavior. + // Default: "false" + CirconusCheckForceMetricActivation string `hcl:"circonus_check_force_metric_activation"` + // CirconusCheckInstanceID serves to uniquely identify the metrics coming from this "instance". + // It can be used to maintain metric continuity with transient or ephemeral instances as + // they move around within an infrastructure. + // Default: hostname:app + CirconusCheckInstanceID string `hcl:"circonus_check_instance_id"` + // CirconusCheckSearchTag is a special tag which, when coupled with the instance id, helps to + // narrow down the search results when neither a Submission URL or Check ID is provided. + // Default: service:app (e.g. service:consul) + CirconusCheckSearchTag string `hcl:"circonus_check_search_tag"` + // CirconusCheckTags is a comma separated list of tags to apply to the check. Note that + // the value of CirconusCheckSearchTag will always be added to the check. + // Default: none + CirconusCheckTags string `hcl:"circonus_check_tags"` + // CirconusCheckDisplayName is the name for the check which will be displayed in the Circonus UI. + // Default: value of CirconusCheckInstanceID + CirconusCheckDisplayName string `hcl:"circonus_check_display_name"` + // CirconusBrokerID is an explicit broker to use when creating a new check. The numeric portion + // of broker._cid. If metric management is enabled and neither a Submission URL nor Check ID + // is provided, an attempt will be made to search for an existing check using Instance ID and + // Search Tag. If one is not found, a new HTTPTRAP check will be created. + // Default: use Select Tag if provided, otherwise, a random Enterprise Broker associated + // with the specified API token or the default Circonus Broker. + // Default: none + CirconusBrokerID string `hcl:"circonus_broker_id"` + // CirconusBrokerSelectTag is a special tag which will be used to select a broker when + // a Broker ID is not provided. The best use of this is to as a hint for which broker + // should be used based on *where* this particular instance is running. + // (e.g. a specific geo location or datacenter, dc:sfo) + // Default: none + CirconusBrokerSelectTag string `hcl:"circonus_broker_select_tag"` + + // Dogstats: + // DogStatsdAddr is the address of a dogstatsd instance. If provided, + // metrics will be sent to that instance + DogStatsDAddr string `hcl:"dogstatsd_addr"` + + // DogStatsdTags are the global tags that should be sent with each packet to dogstatsd + // It is a list of strings, where each string looks like "my_tag_name:my_tag_value" + DogStatsDTags []string `hcl:"dogstatsd_tags"` + + // Prometheus: + // PrometheusRetentionTime is the retention time for prometheus metrics if greater than 0. + // Default: 24h + PrometheusRetentionTime time.Duration `hcl:"-"` + PrometheusRetentionTimeRaw interface{} `hcl:"prometheus_retention_time"` + + // Stackdriver: + // StackdriverProjectID is the project to publish stackdriver metrics to. + StackdriverProjectID string `hcl:"stackdriver_project_id"` + // StackdriverLocation is the GCP or AWS region of the monitored resource. + StackdriverLocation string `hcl:"stackdriver_location"` + // StackdriverNamespace is the namespace identifier, such as a cluster name. + StackdriverNamespace string `hcl:"stackdriver_namespace"` + // StackdriverDebugLogs will write additional stackdriver related debug logs to stderr. + StackdriverDebugLogs bool `hcl:"stackdriver_debug_logs"` +} + +func (t *Telemetry) GoString() string { + return fmt.Sprintf("*%#v", *t) +} + +func parseTelemetry(result *SharedConfig, list *ast.ObjectList) error { + if len(list.Items) > 1 { + return fmt.Errorf("only one 'telemetry' block is permitted") + } + + // Get our one item + item := list.Items[0] + + var t Telemetry + if err := hcl.DecodeObject(&t, item.Val); err != nil { + return multierror.Prefix(err, "telemetry:") + } + + if result.Telemetry == nil { + result.Telemetry = &Telemetry{} + } + + if err := hcl.DecodeObject(&result.Telemetry, item.Val); err != nil { + return multierror.Prefix(err, "telemetry:") + } + + if result.Telemetry.PrometheusRetentionTimeRaw != nil { + var err error + if result.Telemetry.PrometheusRetentionTime, err = parseutil.ParseDurationSecond(result.Telemetry.PrometheusRetentionTimeRaw); err != nil { + return err + } + result.Telemetry.PrometheusRetentionTimeRaw = nil + } else { + result.Telemetry.PrometheusRetentionTime = PrometheusDefaultRetentionTime + } + + return nil +} + +type SetupTelemetryOpts struct { + Config *Telemetry + Ui cli.Ui + ServiceName string + DisplayName string + UserAgent string + ClusterName string +} + +// SetupTelemetry is used to setup the telemetry sub-systems and returns the +// in-memory sink to be used in http configuration +func SetupTelemetry(opts *SetupTelemetryOpts) (*metrics.InmemSink, *metricsutil.ClusterMetricSink, bool, error) { + if opts == nil { + return nil, nil, false, errors.New("nil opts passed into SetupTelemetry") + } + + if opts.Config == nil { + opts.Config = &Telemetry{} + } + + /* Setup telemetry + Aggregate on 10 second intervals for 1 minute. Expose the + metrics over stderr when there is a SIGUSR1 received. + */ + inm := metrics.NewInmemSink(10*time.Second, time.Minute) + metrics.DefaultInmemSignal(inm) + + if opts.Config.MetricsPrefix != "" { + opts.ServiceName = opts.Config.MetricsPrefix + } + + metricsConf := metrics.DefaultConfig(opts.ServiceName) + metricsConf.EnableHostname = !opts.Config.DisableHostname + metricsConf.EnableHostnameLabel = opts.Config.EnableHostnameLabel + + // Configure the statsite sink + var fanout metrics.FanoutSink + var prometheusEnabled bool + + // Configure the Prometheus sink + if opts.Config.PrometheusRetentionTime != 0 { + prometheusEnabled = true + prometheusOpts := prometheus.PrometheusOpts{ + Expiration: opts.Config.PrometheusRetentionTime, + } + + sink, err := prometheus.NewPrometheusSinkFrom(prometheusOpts) + if err != nil { + return nil, nil, false, err + } + fanout = append(fanout, sink) + } + + if opts.Config.StatsiteAddr != "" { + sink, err := metrics.NewStatsiteSink(opts.Config.StatsiteAddr) + if err != nil { + return nil, nil, false, err + } + fanout = append(fanout, sink) + } + + // Configure the statsd sink + if opts.Config.StatsdAddr != "" { + sink, err := metrics.NewStatsdSink(opts.Config.StatsdAddr) + if err != nil { + return nil, nil, false, err + } + fanout = append(fanout, sink) + } + + // Configure the Circonus sink + if opts.Config.CirconusAPIToken != "" || opts.Config.CirconusCheckSubmissionURL != "" { + cfg := &circonus.Config{} + cfg.Interval = opts.Config.CirconusSubmissionInterval + cfg.CheckManager.API.TokenKey = opts.Config.CirconusAPIToken + cfg.CheckManager.API.TokenApp = opts.Config.CirconusAPIApp + cfg.CheckManager.API.URL = opts.Config.CirconusAPIURL + cfg.CheckManager.Check.SubmissionURL = opts.Config.CirconusCheckSubmissionURL + cfg.CheckManager.Check.ID = opts.Config.CirconusCheckID + cfg.CheckManager.Check.ForceMetricActivation = opts.Config.CirconusCheckForceMetricActivation + cfg.CheckManager.Check.InstanceID = opts.Config.CirconusCheckInstanceID + cfg.CheckManager.Check.SearchTag = opts.Config.CirconusCheckSearchTag + cfg.CheckManager.Check.DisplayName = opts.Config.CirconusCheckDisplayName + cfg.CheckManager.Check.Tags = opts.Config.CirconusCheckTags + cfg.CheckManager.Broker.ID = opts.Config.CirconusBrokerID + cfg.CheckManager.Broker.SelectTag = opts.Config.CirconusBrokerSelectTag + + if cfg.CheckManager.API.TokenApp == "" { + cfg.CheckManager.API.TokenApp = opts.ServiceName + } + + if cfg.CheckManager.Check.DisplayName == "" { + cfg.CheckManager.Check.DisplayName = opts.DisplayName + } + + if cfg.CheckManager.Check.SearchTag == "" { + cfg.CheckManager.Check.SearchTag = fmt.Sprintf("service:%s", opts.ServiceName) + } + + sink, err := circonus.NewCirconusSink(cfg) + if err != nil { + return nil, nil, false, err + } + sink.Start() + fanout = append(fanout, sink) + } + + if opts.Config.DogStatsDAddr != "" { + var tags []string + + if opts.Config.DogStatsDTags != nil { + tags = opts.Config.DogStatsDTags + } + + sink, err := datadog.NewDogStatsdSink(opts.Config.DogStatsDAddr, metricsConf.HostName) + if err != nil { + return nil, nil, false, errwrap.Wrapf("failed to start DogStatsD sink: {{err}}", err) + } + sink.SetTags(tags) + fanout = append(fanout, sink) + } + + // Configure the stackdriver sink + if opts.Config.StackdriverProjectID != "" { + client, err := monitoring.NewMetricClient(context.Background(), option.WithUserAgent(opts.UserAgent)) + if err != nil { + return nil, nil, false, fmt.Errorf("Failed to create stackdriver client: %v", err) + } + sink := stackdriver.NewSink(client, &stackdriver.Config{ + LabelExtractor: stackdrivervault.Extractor, + Bucketer: stackdrivervault.Bucketer, + ProjectID: opts.Config.StackdriverProjectID, + Location: opts.Config.StackdriverLocation, + Namespace: opts.Config.StackdriverNamespace, + DebugLogs: opts.Config.StackdriverDebugLogs, + }) + fanout = append(fanout, sink) + } + + // Initialize the global sink + if len(fanout) > 1 { + // Hostname enabled will create poor quality metrics name for prometheus + if !opts.Config.DisableHostname { + opts.Ui.Warn("telemetry.disable_hostname has been set to false. Recommended setting is true for Prometheus to avoid poorly named metrics.") + } + } else { + metricsConf.EnableHostname = false + } + fanout = append(fanout, inm) + _, err := metrics.NewGlobal(metricsConf, fanout) + + if err != nil { + return nil, nil, false, err + } + + // Intialize a wrapper around the global sink; this will be passed to Core + // and to any backend. + wrapper := &metricsutil.ClusterMetricSink{ + ClusterName: opts.ClusterName, + MaxGaugeCardinality: 500, + GaugeInterval: 10 * time.Minute, + Sink: fanout, + } + + return inm, wrapper, prometheusEnabled, nil +} diff --git a/internalshared/listenerutil/listener.go b/internalshared/listenerutil/listener.go index 93e5b26b88..c72342c22b 100644 --- a/internalshared/listenerutil/listener.go +++ b/internalshared/listenerutil/listener.go @@ -11,13 +11,18 @@ import ( "strconv" "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/internalshared/reloadutil" - "github.com/hashicorp/vault/sdk/helper/parseutil" "github.com/hashicorp/vault/sdk/helper/tlsutil" "github.com/jefferai/isbadcipher" "github.com/mitchellh/cli" ) +type Listener struct { + net.Listener + Config *configutil.Listener +} + type UnixSocketsConfig struct { User string `hcl:"user"` Mode string `hcl:"mode"` @@ -67,92 +72,69 @@ func UnixSocketListener(path string, unixSocketsConfig *UnixSocketsConfig) (net. }, nil } -func WrapTLS( - ln net.Listener, +func TLSConfig( + l *configutil.Listener, props map[string]string, - config map[string]interface{}, - ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, *tls.Config, error) { + ui cli.Ui) (*tls.Config, reloadutil.ReloadFunc, error) { props["tls"] = "disabled" - if v, ok := config["tls_disable"]; ok { - disabled, err := parseutil.ParseBool(v) - if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_disable': {{err}}", err) - } - if disabled { - return ln, props, nil, nil, nil - } + if l.TLSDisable { + return nil, nil, nil } - certFileRaw, ok := config["tls_cert_file"] - if !ok { - return nil, nil, nil, nil, fmt.Errorf("'tls_cert_file' must be set") - } - certFile := certFileRaw.(string) - keyFileRaw, ok := config["tls_key_file"] - if !ok { - return nil, nil, nil, nil, fmt.Errorf("'tls_key_file' must be set") - } - keyFile := keyFileRaw.(string) - - cg := reloadutil.NewCertificateGetter(certFile, keyFile, "") - if err := cg.Reload(config); err != nil { + cg := reloadutil.NewCertificateGetter(l.TLSCertFile, l.TLSKeyFile, "") + if err := cg.Reload(); err != nil { // We try the key without a passphrase first and if we get an incorrect // passphrase response, try again after prompting for a passphrase if errwrap.Contains(err, x509.IncorrectPasswordError.Error()) { var passphrase string - passphrase, err = ui.AskSecret(fmt.Sprintf("Enter passphrase for %s:", keyFile)) + passphrase, err = ui.AskSecret(fmt.Sprintf("Enter passphrase for %s:", l.TLSKeyFile)) if err == nil { - cg = reloadutil.NewCertificateGetter(certFile, keyFile, passphrase) - if err = cg.Reload(config); err == nil { + cg = reloadutil.NewCertificateGetter(l.TLSCertFile, l.TLSKeyFile, passphrase) + if err = cg.Reload(); err == nil { goto PASSPHRASECORRECT } } } - return nil, nil, nil, nil, errwrap.Wrapf("error loading TLS cert: {{err}}", err) + return nil, nil, errwrap.Wrapf("error loading TLS cert: {{err}}", err) } PASSPHRASECORRECT: - var tlsvers string - tlsversRaw, ok := config["tls_min_version"] - if !ok { - tlsvers = "tls12" - } else { - tlsvers = tlsversRaw.(string) + tlsConf := &tls.Config{ + GetCertificate: cg.GetCertificate, + NextProtos: []string{"h2", "http/1.1"}, + ClientAuth: tls.RequestClientCert, + PreferServerCipherSuites: l.TLSPreferServerCipherSuites, } - tlsConf := &tls.Config{} - tlsConf.GetCertificate = cg.GetCertificate - tlsConf.NextProtos = []string{"h2", "http/1.1"} - tlsConf.MinVersion, ok = tlsutil.TLSLookup[tlsvers] - if !ok { - return nil, nil, nil, nil, fmt.Errorf("'tls_min_version' value %q not supported, please specify one of [tls10,tls11,tls12,tls13]", tlsvers) + if l.TLSMinVersion == "" { + l.TLSMinVersion = "tls12" } - tlsConf.ClientAuth = tls.RequestClientCert - if v, ok := config["tls_cipher_suites"]; ok { - ciphers, err := tlsutil.ParseCiphers(v.(string)) - if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_cipher_suites': {{err}}", err) - } + var ok bool + tlsConf.MinVersion, ok = tlsutil.TLSLookup[l.TLSMinVersion] + if !ok { + return nil, nil, fmt.Errorf("'tls_min_version' value %q not supported, please specify one of [tls10,tls11,tls12,tls13]", l.TLSMinVersion) + } + if len(l.TLSCipherSuites) > 0 { // HTTP/2 with TLS 1.2 blacklists several cipher suites. // https://tools.ietf.org/html/rfc7540#appendix-A // // Since the CLI (net/http) automatically uses HTTP/2 with TLS 1.2, // we check here if all or some specified cipher suites are blacklisted. badCiphers := []string{} - for _, cipher := range ciphers { + for _, cipher := range l.TLSCipherSuites { if isbadcipher.IsBadCipher(cipher) { // Get the name of the current cipher. cipherStr, err := tlsutil.GetCipherName(cipher) if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_cipher_suites': {{err}}", err) + return nil, nil, errwrap.Wrapf("invalid value for 'tls_cipher_suites': {{err}}", err) } badCiphers = append(badCiphers, cipherStr) } } - if len(badCiphers) == len(ciphers) { + if len(badCiphers) == len(l.TLSCipherSuites) { ui.Warn(`WARNING! All cipher suites defined by 'tls_cipher_suites' are blacklisted by the HTTP/2 specification. HTTP/2 communication with TLS 1.2 will not work as intended and Vault will be unavailable via the CLI. @@ -163,54 +145,34 @@ blacklisted by the HTTP/2 specification: %v Please see https://tools.ietf.org/html/rfc7540#appendix-A for further information.`, badCiphers)) } - tlsConf.CipherSuites = ciphers + tlsConf.CipherSuites = l.TLSCipherSuites } - if v, ok := config["tls_prefer_server_cipher_suites"]; ok { - preferServer, err := parseutil.ParseBool(v) - if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_prefer_server_cipher_suites': {{err}}", err) - } - tlsConf.PreferServerCipherSuites = preferServer - } - var requireVerifyCerts bool - var err error - if v, ok := config["tls_require_and_verify_client_cert"]; ok { - requireVerifyCerts, err = parseutil.ParseBool(v) - if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_require_and_verify_client_cert': {{err}}", err) - } - if requireVerifyCerts { - tlsConf.ClientAuth = tls.RequireAndVerifyClientCert - } - if tlsClientCaFile, ok := config["tls_client_ca_file"]; ok { + + if l.TLSRequireAndVerifyClientCert { + tlsConf.ClientAuth = tls.RequireAndVerifyClientCert + if l.TLSClientCAFile != "" { caPool := x509.NewCertPool() - data, err := ioutil.ReadFile(tlsClientCaFile.(string)) + data, err := ioutil.ReadFile(l.TLSClientCAFile) if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("failed to read tls_client_ca_file: {{err}}", err) + return nil, nil, errwrap.Wrapf("failed to read tls_client_ca_file: {{err}}", err) } if !caPool.AppendCertsFromPEM(data) { - return nil, nil, nil, nil, fmt.Errorf("failed to parse CA certificate in tls_client_ca_file") + return nil, nil, fmt.Errorf("failed to parse CA certificate in tls_client_ca_file") } tlsConf.ClientCAs = caPool } } - if v, ok := config["tls_disable_client_certs"]; ok { - disableClientCerts, err := parseutil.ParseBool(v) - if err != nil { - return nil, nil, nil, nil, errwrap.Wrapf("invalid value for 'tls_disable_client_certs': {{err}}", err) - } - if disableClientCerts && requireVerifyCerts { - return nil, nil, nil, nil, fmt.Errorf("'tls_disable_client_certs' and 'tls_require_and_verify_client_cert' are mutually exclusive") - } - if disableClientCerts { - tlsConf.ClientAuth = tls.NoClientCert + + if l.TLSDisableClientCerts { + if l.TLSRequireAndVerifyClientCert { + return nil, nil, fmt.Errorf("'tls_disable_client_certs' and 'tls_require_and_verify_client_cert' are mutually exclusive") } + tlsConf.ClientAuth = tls.NoClientCert } - ln = tls.NewListener(ln, tlsConf) props["tls"] = "enabled" - return ln, props, cg.Reload, tlsConf, nil + return tlsConf, cg.Reload, nil } // setFilePermissions handles configuring ownership and permissions diff --git a/internalshared/reloadutil/reload.go b/internalshared/reloadutil/reload.go index 4938b9cce3..13dbf1fc51 100644 --- a/internalshared/reloadutil/reload.go +++ b/internalshared/reloadutil/reload.go @@ -13,7 +13,7 @@ import ( ) // ReloadFunc are functions that are called when a reload is requested -type ReloadFunc func(map[string]interface{}) error +type ReloadFunc func() error // CertificateGetter satisfies ReloadFunc and its GetCertificate method // satisfies the tls.GetCertificate function signature. Currently it does not @@ -36,7 +36,7 @@ func NewCertificateGetter(certFile, keyFile, passphrase string) *CertificateGett } } -func (cg *CertificateGetter) Reload(_ map[string]interface{}) error { +func (cg *CertificateGetter) Reload() error { certPEMBlock, err := ioutil.ReadFile(cg.certFile) if err != nil { return err diff --git a/internalshared/reloadutil/reload_test.go b/internalshared/reloadutil/reload_test.go index ed4cc0c02f..872ab37168 100644 --- a/internalshared/reloadutil/reload_test.go +++ b/internalshared/reloadutil/reload_test.go @@ -59,7 +59,7 @@ opM24uvQT3Bc0UM0WNh3tdRFuboxDeBDh7PX/2RIoiaMuCCiRZ3O0A== } cg := NewCertificateGetter(certFile, keyFile, "") - err = cg.Reload(nil) + err = cg.Reload() if err == nil { t.Fatal("error expected") } @@ -68,7 +68,7 @@ opM24uvQT3Bc0UM0WNh3tdRFuboxDeBDh7PX/2RIoiaMuCCiRZ3O0A== } cg = NewCertificateGetter(certFile, keyFile, password) - if err := cg.Reload(nil); err != nil { + if err := cg.Reload(); err != nil { t.Fatalf("err: %v", err) } } diff --git a/vault/audit.go b/vault/audit.go index 636619413f..3c5df35bc2 100644 --- a/vault/audit.go +++ b/vault/audit.go @@ -473,7 +473,7 @@ func (c *Core) newAuditBackend(ctx context.Context, entry *MountEntry, view logi } } - c.reloadFuncs[key] = append(c.reloadFuncs[key], func(map[string]interface{}) error { + c.reloadFuncs[key] = append(c.reloadFuncs[key], func() error { if auditLogger.IsInfo() { auditLogger.Info("reloading file audit backend", "path", entry.Path) } diff --git a/vault/core.go b/vault/core.go index 48e7ff6b23..a41f4823f3 100644 --- a/vault/core.go +++ b/vault/core.go @@ -829,7 +829,7 @@ func NewCore(conf *CoreConfig) (*Core, error) { if c.seal == nil { c.seal = NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: c.logger.Named("shamir"), }), }) @@ -1069,7 +1069,7 @@ func (c *Core) unseal(key []byte, useRecoveryKeys bool) (bool, error) { if sealToUse.BarrierType() == wrapping.Shamir && c.migrationInfo == nil { // If this is a legacy shamir seal this serves no purpose but it // doesn't hurt. - err = sealToUse.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(masterKey) + err = sealToUse.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(masterKey) if err != nil { return false, err } @@ -1286,7 +1286,7 @@ func (c *Core) unsealPart(ctx context.Context, seal Seal, key []byte, useRecover c.migrationInfo.shamirCombinedKey = make([]byte, len(recoveredKey)) copy(c.migrationInfo.shamirCombinedKey, recoveredKey) if seal.StoredKeysSupported() == vaultseal.StoredKeysSupportedShamirMaster { - err = seal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(recoveredKey) + err = seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(recoveredKey) if err != nil { return nil, errwrap.Wrapf("failed to set master key in seal: {{err}}", err) } @@ -1360,7 +1360,7 @@ func (c *Core) migrateSeal(ctx context.Context) error { // We have recovery keys; we're going to use them as the new // shamir KeK. - err := c.seal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(c.migrationInfo.recoveryKey) + err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(c.migrationInfo.recoveryKey) if err != nil { return errwrap.Wrapf("failed to set master key in seal: {{err}}", err) } @@ -2264,7 +2264,7 @@ func (c *Core) unsealKeyToMasterKey(ctx context.Context, combinedKey []byte) ([] case vaultseal.StoredKeysSupportedShamirMaster: testseal := NewDefaultSeal(&vaultseal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: c.logger.Named("testseal"), }), }) @@ -2274,7 +2274,7 @@ func (c *Core) unsealKeyToMasterKey(ctx context.Context, combinedKey []byte) ([] return nil, errwrap.Wrapf("failed to setup test barrier config: {{err}}", err) } testseal.SetCachedBarrierConfig(cfg) - err = testseal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(combinedKey) + err = testseal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(combinedKey) if err != nil { return nil, errwrap.Wrapf("failed to setup unseal key: {{err}}", err) } diff --git a/vault/ha.go b/vault/ha.go index 9ddb6b81b3..63ea7e84da 100644 --- a/vault/ha.go +++ b/vault/ha.go @@ -817,7 +817,7 @@ func (c *Core) reloadShamirKey(ctx context.Context) error { } shamirKey = keyring.masterKey } - return c.seal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(shamirKey) + return c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(shamirKey) } func (c *Core) performKeyUpgrades(ctx context.Context) error { diff --git a/vault/identity_store_entities.go b/vault/identity_store_entities.go index 4f23896158..0b89aebf58 100644 --- a/vault/identity_store_entities.go +++ b/vault/identity_store_entities.go @@ -517,7 +517,7 @@ func (i *IdentityStore) handleEntityBatchDelete() framework.OperationFunc { defer i.lock.Unlock() // Create a MemDB transaction to delete entities from the inmem database - // without altering storage. Batch deletion on storage bucket items is + // without altering storage. Batch deletion on storage bucket items is // performed directly through entityPacker. txn := i.db.Txn(true) defer txn.Abort() diff --git a/vault/init.go b/vault/init.go index 69a601ccfe..2fd8a2548f 100644 --- a/vault/init.go +++ b/vault/init.go @@ -303,7 +303,7 @@ func (c *Core) Initialize(ctx context.Context, initParams *InitParams) (*InitRes switch c.seal.StoredKeysSupported() { case seal.StoredKeysSupportedShamirMaster: keysToStore := [][]byte{barrierKey} - if err := c.seal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(sealKey); err != nil { + if err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(sealKey); err != nil { c.logger.Error("failed to set seal key", "error", err) return nil, errwrap.Wrapf("failed to set seal key: {{err}}", err) } diff --git a/vault/rekey.go b/vault/rekey.go index cbaca02b6d..bc5aba05c7 100644 --- a/vault/rekey.go +++ b/vault/rekey.go @@ -400,12 +400,12 @@ func (c *Core) BarrierRekeyUpdate(ctx context.Context, key []byte, nonce string) case c.seal.BarrierType() == wrapping.Shamir: if c.seal.StoredKeysSupported() == seal.StoredKeysSupportedShamirMaster { testseal := NewDefaultSeal(&seal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: c.logger.Named("testseal"), }), }) testseal.SetCore(c) - err = testseal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(recoveredKey) + err = testseal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(recoveredKey) if err != nil { return nil, logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to setup unseal key: {{err}}", err).Error()) } @@ -533,7 +533,7 @@ func (c *Core) performBarrierRekey(ctx context.Context, newSealKey []byte) logic } if c.seal.StoredKeysSupported() != seal.StoredKeysSupportedGeneric { - err := c.seal.GetAccess().Wrapper.(*aeadwrapper.Wrapper).SetAESGCMKeyBytes(newSealKey) + err := c.seal.GetAccess().Wrapper.(*aeadwrapper.ShamirWrapper).SetAESGCMKeyBytes(newSealKey) if err != nil { return logical.CodedError(http.StatusInternalServerError, errwrap.Wrapf("failed to update barrier seal key: {{err}}", err).Error()) } diff --git a/vault/request_handling.go b/vault/request_handling.go index 0dae4e3099..1209c8df59 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -14,6 +14,7 @@ import ( sockaddr "github.com/hashicorp/go-sockaddr" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/errutil" @@ -40,13 +41,11 @@ var ( // HandlerProperties is used to seed configuration into a vaulthttp.Handler. // It's in this package to avoid a circular dependency type HandlerProperties struct { - Core *Core - MaxRequestSize int64 - MaxRequestDuration time.Duration - DisablePrintableCheck bool - RecoveryMode bool - RecoveryToken *uberAtomic.String - UnauthenticatedMetricsAccess bool + Core *Core + ListenerConfig *configutil.Listener + DisablePrintableCheck bool + RecoveryMode bool + RecoveryToken *uberAtomic.String } // fetchEntityAndDerivedPolicies returns the entity object for the given entity diff --git a/vault/seal_testing_util.go b/vault/seal_testing_util.go index 44e172ae60..b5379f3ae6 100644 --- a/vault/seal_testing_util.go +++ b/vault/seal_testing_util.go @@ -21,7 +21,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal { switch opts.StoredKeys { case seal.StoredKeysSupportedShamirMaster: newSeal := NewDefaultSeal(&seal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: opts.Logger, }), }) @@ -34,7 +34,7 @@ func NewTestSeal(t testing.T, opts *seal.TestSealOpts) Seal { return newSeal case seal.StoredKeysNotSupported: newSeal := NewDefaultSeal(&seal.Access{ - Wrapper: aeadwrapper.NewWrapper(&wrapping.WrapperOptions{ + Wrapper: aeadwrapper.NewShamirWrapper(&wrapping.WrapperOptions{ Logger: opts.Logger, }), }) diff --git a/vault/testing.go b/vault/testing.go index dc392fdf11..f1b4542f62 100644 --- a/vault/testing.go +++ b/vault/testing.go @@ -1370,7 +1370,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te } certGetter := reloadutil.NewCertificateGetter(certFile, keyFile, "") certGetters = append(certGetters, certGetter) - certGetter.Reload(nil) + certGetter.Reload() tlsConfig := &tls.Config{ Certificates: []tls.Certificate{tlsCert}, RootCAs: testCluster.RootCAs, @@ -1590,8 +1590,8 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te if opts != nil && opts.HandlerFunc != nil { props := opts.DefaultHandlerProperties props.Core = c - if props.MaxRequestDuration == 0 { - props.MaxRequestDuration = DefaultMaxRequestDuration + if props.ListenerConfig != nil && props.ListenerConfig.MaxRequestDuration == 0 { + props.ListenerConfig.MaxRequestDuration = DefaultMaxRequestDuration } handlers[i] = opts.HandlerFunc(&props) servers[i].Handler = handlers[i]