From bfaf9022fa7e0cd6290de1315a24ef20d5719216 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 24 Feb 2017 10:45:29 -0500 Subject: [PATCH] Do some porting to make diffing easier --- command/server.go | 45 +++++++----- command/server/config.go | 73 +++++++++++++++++++ command/server/config_test.go | 6 ++ .../server/test-fixtures/config-dir/bar.json | 2 + .../server/test-fixtures/config-dir/baz.hcl | 2 +- command/server/test-fixtures/config.hcl | 2 + command/server/test-fixtures/config.hcl.json | 3 +- command/server/test-fixtures/config2.hcl.json | 1 + vault/core.go | 8 +- vault/rekey.go | 20 +++++ vault/router_test.go | 4 +- vault/testing.go | 29 ++++++++ 12 files changed, 172 insertions(+), 23 deletions(-) diff --git a/command/server.go b/command/server.go index e0b81f90a4..8f0a52efd3 100644 --- a/command/server.go +++ b/command/server.go @@ -302,6 +302,9 @@ func (c *ServerCommand) Run(args []string) int { coreConfig.RedirectAddr = redirect } } + if coreConfig.RedirectAddr == "" && dev { + coreConfig.RedirectAddr = fmt.Sprintf("http://%s", config.Listeners[0].Config["address"]) + } // After the redirect bits are sorted out, if no cluster address was // explicitly given, derive one from the redirect addr @@ -309,10 +312,16 @@ func (c *ServerCommand) Run(args []string) int { coreConfig.ClusterAddr = "" } else if envCA := os.Getenv("VAULT_CLUSTER_ADDR"); envCA != "" { coreConfig.ClusterAddr = envCA - } else if coreConfig.ClusterAddr == "" && coreConfig.RedirectAddr != "" { - u, err := url.ParseRequestURI(coreConfig.RedirectAddr) + } else { + var addrToUse string + if coreConfig.ClusterAddr == "" && coreConfig.RedirectAddr != "" { + addrToUse = coreConfig.RedirectAddr + } else if dev { + addrToUse = fmt.Sprintf("http://%s", config.Listeners[0].Config["address"]) + } + u, err := url.ParseRequestURI(addrToUse) if err != nil { - c.Ui.Output(fmt.Sprintf("Error parsing redirect address %s: %v", coreConfig.RedirectAddr, err)) + c.Ui.Output(fmt.Sprintf("Error parsing synthesized cluster address %s: %v", addrToUse, err)) return 1 } host, port, err := net.SplitHostPort(u.Host) @@ -328,7 +337,7 @@ func (c *ServerCommand) Run(args []string) int { } nPort, err := strconv.Atoi(port) if err != nil { - c.Ui.Output(fmt.Sprintf("Error parsing redirect address; failed to convert %q to a numeric: %v", port, err)) + c.Ui.Output(fmt.Sprintf("Error parsing synthesized address; failed to convert %q to a numeric: %v", port, err)) return 1 } u.Host = net.JoinHostPort(host, strconv.Itoa(nPort+1)) @@ -368,25 +377,23 @@ func (c *ServerCommand) Run(args []string) int { mlock.Supported(), !config.DisableMlock && mlock.Supported()) infoKeys = append(infoKeys, "log level", "mlock", "backend") + if coreConfig.ClusterAddr != "" { + info["cluster address"] = coreConfig.ClusterAddr + infoKeys = append(infoKeys, "cluster address") + } + if coreConfig.RedirectAddr != "" { + info["redirect address"] = coreConfig.RedirectAddr + infoKeys = append(infoKeys, "redirect address") + } + if config.HABackend != nil { info["HA backend"] = config.HABackend.Type - info["redirect address"] = coreConfig.RedirectAddr - infoKeys = append(infoKeys, "HA backend", "redirect address") - if coreConfig.ClusterAddr != "" { - info["cluster address"] = coreConfig.ClusterAddr - infoKeys = append(infoKeys, "cluster address") - } + infoKeys = append(infoKeys, "HA backend") } else { // If the backend supports HA, then note it if coreConfig.HAPhysical != nil { if coreConfig.HAPhysical.HAEnabled() { info["backend"] += " (HA available)" - info["redirect address"] = coreConfig.RedirectAddr - infoKeys = append(infoKeys, "redirect address") - if coreConfig.ClusterAddr != "" { - info["cluster address"] = coreConfig.ClusterAddr - infoKeys = append(infoKeys, "cluster address") - } } else { info["backend"] += " (HA disabled)" } @@ -442,10 +449,12 @@ func (c *ServerCommand) Run(args []string) int { c.Ui.Output("Failed to parse tcp listener") return 1 } - clusterAddrs = append(clusterAddrs, &net.TCPAddr{ + clusterAddr := &net.TCPAddr{ IP: tcpAddr.IP, Port: tcpAddr.Port + 1, - }) + } + clusterAddrs = append(clusterAddrs, clusterAddr) + addr = clusterAddr.String() } props["cluster address"] = addr } diff --git a/command/server/config.go b/command/server/config.go index 77bece5b7f..00edd5de93 100644 --- a/command/server/config.go +++ b/command/server/config.go @@ -23,10 +23,14 @@ type Config struct { Backend *Backend `hcl:"-"` HABackend *Backend `hcl:"-"` + HSM *HSM `hcl:"-"` + CacheSize int `hcl:"cache_size"` DisableCache bool `hcl:"disable_cache"` DisableMlock bool `hcl:"disable_mlock"` + EnableUI bool `hcl:"ui"` + Telemetry *Telemetry `hcl:"telemetry"` MaxLeaseTTL time.Duration `hcl:"-"` @@ -57,6 +61,8 @@ func DevConfig(ha, transactional bool) *Config { }, }, + EnableUI: true, + Telemetry: &Telemetry{}, MaxLeaseTTL: 32 * 24 * time.Hour, @@ -98,6 +104,16 @@ func (b *Backend) GoString() string { return fmt.Sprintf("*%#v", *b) } +// HSM contains HSM configuration for the server +type HSM struct { + Type string + Config map[string]string +} + +func (h *HSM) GoString() string { + return fmt.Sprintf("*%#v", *h) +} + // Telemetry is the telemetry configuration for the server type Telemetry struct { StatsiteAddr string `hcl:"statsite_address"` @@ -205,6 +221,11 @@ func (c *Config) Merge(c2 *Config) *Config { result.HABackend = c2.HABackend } + result.HSM = c.HSM + if c2.HSM != nil { + result.HSM = c2.HSM + } + result.Telemetry = c.Telemetry if c2.Telemetry != nil { result.Telemetry = c2.Telemetry @@ -242,6 +263,11 @@ func (c *Config) Merge(c2 *Config) *Config { result.ClusterName = c2.ClusterName } + result.EnableUI = c.EnableUI + if c2.EnableUI { + result.EnableUI = c2.EnableUI + } + return result } @@ -303,10 +329,12 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) { "atlas", "backend", "ha_backend", + "hsm", "listener", "cache_size", "disable_cache", "disable_mlock", + "ui", "telemetry", "default_lease_ttl", "max_lease_ttl", @@ -328,6 +356,12 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) { } } + if o := list.Filter("hsm"); len(o.Items) > 0 { + if err := parseHSMs(&result, o); err != nil { + return nil, fmt.Errorf("error parsing 'hsm': %s", err) + } + } + if o := list.Filter("listener"); len(o.Items) > 0 { if err := parseListeners(&result, o); err != nil { return nil, fmt.Errorf("error parsing 'listener': %s", err) @@ -530,6 +564,45 @@ func parseHABackends(result *Config, list *ast.ObjectList) error { return nil } +func parseHSMs(result *Config, list *ast.ObjectList) error { + if len(list.Items) > 1 { + return fmt.Errorf("only one 'hsm' block is permitted") + } + + // Get our item + item := list.Items[0] + + key := "hsm" + if len(item.Keys) > 0 { + key = item.Keys[0].Token.Value().(string) + } + + valid := []string{ + "lib", + "slot", + "pin", + "mechanism", + "key_label", + "generate_key", + "regenerate_key", + } + if err := checkHCLKeys(item.Val, valid); err != nil { + return multierror.Prefix(err, fmt.Sprintf("hsm.%s:", key)) + } + + var m map[string]string + if err := hcl.DecodeObject(&m, item.Val); err != nil { + return multierror.Prefix(err, fmt.Sprintf("hsm.%s:", key)) + } + + result.HSM = &HSM{ + Type: strings.ToLower(key), + Config: m, + } + + return nil +} + func parseListeners(result *Config, list *ast.ObjectList) error { var foundAtlas bool diff --git a/command/server/config_test.go b/command/server/config_test.go index b0e370e071..a0b4794366 100644 --- a/command/server/config_test.go +++ b/command/server/config_test.go @@ -62,6 +62,7 @@ func TestLoadConfigFile(t *testing.T) { DisableCache: true, DisableMlock: true, + EnableUI: true, MaxLeaseTTL: 10 * time.Hour, MaxLeaseTTLRaw: "10h", @@ -133,6 +134,7 @@ func TestLoadConfigFile_json(t *testing.T) { DefaultLeaseTTL: 10 * time.Hour, DefaultLeaseTTLRaw: "10h", ClusterName: "testcluster", + EnableUI: true, } if !reflect.DeepEqual(config, expected) { t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected) @@ -180,6 +182,8 @@ func TestLoadConfigFile_json2(t *testing.T) { CacheSize: 45678, + EnableUI: true, + Telemetry: &Telemetry{ StatsiteAddr: "foo", StatsdAddr: "bar", @@ -232,6 +236,8 @@ func TestLoadConfigDir(t *testing.T) { DisableClustering: true, }, + EnableUI: true, + Telemetry: &Telemetry{ StatsiteAddr: "qux", StatsdAddr: "baz", diff --git a/command/server/test-fixtures/config-dir/bar.json b/command/server/test-fixtures/config-dir/bar.json index 677e81aae1..16055e8375 100644 --- a/command/server/test-fixtures/config-dir/bar.json +++ b/command/server/test-fixtures/config-dir/bar.json @@ -1,4 +1,6 @@ { + "ui":false, + "listener": { "tcp": { "address": "127.0.0.1:443" diff --git a/command/server/test-fixtures/config-dir/baz.hcl b/command/server/test-fixtures/config-dir/baz.hcl index 9b650104b2..7d8864094a 100644 --- a/command/server/test-fixtures/config-dir/baz.hcl +++ b/command/server/test-fixtures/config-dir/baz.hcl @@ -3,6 +3,6 @@ telemetry { statsite_address = "qux" disable_hostname = true } - +ui=true default_lease_ttl = "10h" cluster_name = "testcluster" diff --git a/command/server/test-fixtures/config.hcl b/command/server/test-fixtures/config.hcl index 9ad47900c0..731f0a037e 100644 --- a/command/server/test-fixtures/config.hcl +++ b/command/server/test-fixtures/config.hcl @@ -1,6 +1,8 @@ disable_cache = true disable_mlock = true +ui = true + listener "atlas" { token = "foobar" infrastructure = "foo/bar" diff --git a/command/server/test-fixtures/config.hcl.json b/command/server/test-fixtures/config.hcl.json index 67480965c2..6e37c9a3a1 100644 --- a/command/server/test-fixtures/config.hcl.json +++ b/command/server/test-fixtures/config.hcl.json @@ -22,5 +22,6 @@ }, "max_lease_ttl": "10h", "default_lease_ttl": "10h", - "cluster_name":"testcluster" + "cluster_name":"testcluster", + "ui":true } diff --git a/command/server/test-fixtures/config2.hcl.json b/command/server/test-fixtures/config2.hcl.json index 2df19f9da5..fd3ab6e622 100644 --- a/command/server/test-fixtures/config2.hcl.json +++ b/command/server/test-fixtures/config2.hcl.json @@ -1,4 +1,5 @@ { + "ui":true, "listener":[ { "tcp":{ diff --git a/vault/core.go b/vault/core.go index 5562eb8181..4b858e046f 100644 --- a/vault/core.go +++ b/vault/core.go @@ -320,6 +320,9 @@ type Core struct { // replicationState keeps the current replication state cached for quick // lookup replicationState consts.ReplicationState + + // uiEnabled indicates whether Vault Web UI is enabled or not + uiEnabled bool } // CoreConfig is used to parameterize a core @@ -362,6 +365,8 @@ type CoreConfig struct { ClusterName string `json:"cluster_name" structs:"cluster_name" mapstructure:"cluster_name"` + EnableUI bool `json:"ui" structs:"ui" mapstructure:"ui"` + ReloadFuncs *map[string][]ReloadFunc ReloadFuncsLock *sync.RWMutex } @@ -403,9 +408,10 @@ func NewCore(conf *CoreConfig) (*Core, error) { // Setup the core c := &Core{ + devToken: conf.DevToken, + physical: conf.Physical, redirectAddr: conf.RedirectAddr, clusterAddr: conf.ClusterAddr, - physical: conf.Physical, seal: conf.Seal, router: NewRouter(), sealed: true, diff --git a/vault/rekey.go b/vault/rekey.go index 50f683b6b2..adebf099d2 100644 --- a/vault/rekey.go +++ b/vault/rekey.go @@ -411,6 +411,16 @@ func (c *Core) BarrierRekeyUpdate(key []byte, nonce string) (*RekeyResult, error return nil, fmt.Errorf("failed to save rekey seal configuration: %v", err) } + // Write to the canary path, which will force a synchronous truing during + // replication + if err := c.barrier.Put(&Entry{ + Key: coreKeyringCanaryPath, + Value: []byte(c.barrierRekeyConfig.Nonce), + }); err != nil { + c.logger.Error("core: error saving keyring canary", "error", err) + return nil, fmt.Errorf("failed to save keyring canary: %v", err) + } + // Done! c.barrierRekeyProgress = nil c.barrierRekeyConfig = nil @@ -579,6 +589,16 @@ func (c *Core) RecoveryRekeyUpdate(key []byte, nonce string) (*RekeyResult, erro return nil, fmt.Errorf("failed to save rekey seal configuration: %v", err) } + // Write to the canary path, which will force a synchronous truing during + // replication + if err := c.barrier.Put(&Entry{ + Key: coreKeyringCanaryPath, + Value: []byte(c.recoveryRekeyConfig.Nonce), + }); err != nil { + c.logger.Error("core: error saving keyring canary", "error", err) + return nil, fmt.Errorf("failed to save keyring canary: %v", err) + } + // Done! c.recoveryRekeyProgress = nil c.recoveryRekeyConfig = nil diff --git a/vault/router_test.go b/vault/router_test.go index 912aa0116d..5ba274bc8e 100644 --- a/vault/router_test.go +++ b/vault/router_test.go @@ -58,8 +58,8 @@ func (n *NoopBackend) Cleanup() { // noop } -func (n *NoopBackend) InvalidateKey(string) { - // noop +func (n *NoopBackend) InvalidateKey(k string) { + n.Invalidations = append(n.Invalidations, k) } func (n *NoopBackend) Initialize() error { diff --git a/vault/testing.go b/vault/testing.go index 2229c7b996..755875d4f4 100644 --- a/vault/testing.go +++ b/vault/testing.go @@ -18,8 +18,11 @@ import ( "github.com/mitchellh/copystructure" "golang.org/x/crypto/ssh" + "golang.org/x/net/http2" + cleanhttp "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/audit" "github.com/hashicorp/vault/helper/logformat" "github.com/hashicorp/vault/helper/salt" @@ -508,6 +511,7 @@ type TestClusterCore struct { CACertBytes []byte CACert *x509.Certificate TLSConfig *tls.Config + Client *api.Client } func (t *TestClusterCore) CloseListeners() { @@ -796,6 +800,28 @@ func TestCluster(t testing.TB, handlers []http.Handler, base *CoreConfig, unseal } } + getAPIClient := func(port int) *api.Client { + transport := cleanhttp.DefaultPooledTransport() + transport.TLSClientConfig = tlsConfig + http2.ConfigureTransport(transport) + client := &http.Client{ + Transport: transport, + CheckRedirect: func(*http.Request, []*http.Request) error { + // This can of course be overridden per-test by using its own client + return fmt.Errorf("redirects not allowed in these tests") + }, + } + config := api.DefaultConfig() + config.Address = fmt.Sprintf("https://127.0.0.1:%d", port) + config.HttpClient = client + apiClient, err := api.NewClient(config) + if err != nil { + t.Fatal(err) + } + apiClient.SetToken(root) + return apiClient + } + var ret []*TestClusterCore keyCopies, _ := copystructure.Copy(keys) ret = append(ret, &TestClusterCore{ @@ -806,6 +832,7 @@ func TestCluster(t testing.TB, handlers []http.Handler, base *CoreConfig, unseal CACertBytes: caBytes, CACert: caCert, TLSConfig: tlsConfig, + Client: getAPIClient(c1lns[0].Address.Port), }) keyCopies, _ = copystructure.Copy(keys) @@ -817,6 +844,7 @@ func TestCluster(t testing.TB, handlers []http.Handler, base *CoreConfig, unseal CACertBytes: caBytes, CACert: caCert, TLSConfig: tlsConfig, + Client: getAPIClient(c2lns[0].Address.Port), }) keyCopies, _ = copystructure.Copy(keys) @@ -828,6 +856,7 @@ func TestCluster(t testing.TB, handlers []http.Handler, base *CoreConfig, unseal CACertBytes: caBytes, CACert: caCert, TLSConfig: tlsConfig, + Client: getAPIClient(c3lns[0].Address.Port), }) return ret