From 4738ceee5deaee6412a96516e5be814454631128 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 25 Feb 2021 17:57:10 -0500 Subject: [PATCH] Add TLS certificate and worker tag reloading on SIGHUP (ICU-1142) (ICU-1143) (#959) --- CHANGELOG.md | 12 +- internal/cmd/base/listener.go | 6 +- internal/cmd/base/servers.go | 58 ++++-- internal/cmd/commands.go | 25 +-- .../commands/server/listener_reload_test.go | 163 +++++++++++++++++ internal/cmd/commands/server/server.go | 120 +++++++------ internal/cmd/commands/server/server_test.go | 48 +++++ .../server/test-fixtures/reload/bundle1.pem | 87 +++++++++ .../server/test-fixtures/reload/bundle2.pem | 67 +++++++ .../server/worker_tags_reload_test.go | 165 ++++++++++++++++++ internal/cmd/config/config.go | 6 +- internal/servers/worker/worker.go | 6 +- .../docs/configuration/listener/tcp.mdx | 16 +- website/content/docs/configuration/worker.mdx | 5 +- 14 files changed, 677 insertions(+), 107 deletions(-) create mode 100644 internal/cmd/commands/server/listener_reload_test.go create mode 100644 internal/cmd/commands/server/server_test.go create mode 100644 internal/cmd/commands/server/test-fixtures/reload/bundle1.pem create mode 100644 internal/cmd/commands/server/test-fixtures/reload/bundle2.pem create mode 100644 internal/cmd/commands/server/worker_tags_reload_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ebb35e20..9766930ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. -## Next +## Next (Unreleased) ### Changes/Deprecations @@ -22,6 +22,16 @@ All of these changes are from [PR * cli: All errors, including API errors, are now written to `stderr`. Previously in the default table format, API errors would be written to `stdout`. +### New and Improved + +* server: Officially support reloading TLS parameters on `SIGHUP`. (This likely + worked before but wasn't fully tested.) + ([PR](https://github.com/hashicorp/boundary/pull/959)) +* server: On `SIGHUP`, [worker + tags](https://www.boundaryproject.io/docs/configuration/worker#tags) will be + re-parsed and new values used + ([PR](https://github.com/hashicorp/boundary/pull/959)) + ## 0.1.7 (2021/02/16) *Note* This release fixes an upgrade issue affecting users on Postgres 11 diff --git a/internal/cmd/base/listener.go b/internal/cmd/base/listener.go index a69e3392c..05f8d588a 100644 --- a/internal/cmd/base/listener.go +++ b/internal/cmd/base/listener.go @@ -56,10 +56,10 @@ func NewListener(l *configutil.Listener, logger hclog.Logger, ui cli.Ui) (*alpnm return nil, nil, nil, fmt.Errorf("unknown listener type: %q", l.Type) } - var purpose string - if len(l.Purpose) == 1 { - purpose = l.Purpose[0] + if len(l.Purpose) != 1 { + return nil, nil, nil, fmt.Errorf("Expected single listener purpose, found %d", len(l.Purpose)) } + purpose := l.Purpose[0] switch purpose { case "cluster": diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index 2ef292e1b..45a22ad98 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -9,10 +9,12 @@ import ( "io" "net" "os" + "os/signal" "sort" "strconv" "strings" "sync" + "syscall" "github.com/armon/go-metrics" "github.com/hashicorp/boundary/globals" @@ -269,25 +271,26 @@ func (b *Server) SetupListeners(ui cli.Ui, config *configutil.SharedConfig, allo defer b.ReloadFuncsLock.Unlock() for i, lnConfig := range config.Listeners { - var purpose string - for _, p := range lnConfig.Purpose { - purpose = strings.ToLower(p) - if !strutil.StrListContains(allowedPurposes, purpose) { - return fmt.Errorf("Unknown listener purpose %q", purpose) - } + if len(lnConfig.Purpose) != 1 { + return fmt.Errorf("Invalid size of listener purposes (%d)", len(lnConfig.Purpose)) } + purpose := strings.ToLower(lnConfig.Purpose[0]) + if !strutil.StrListContains(allowedPurposes, purpose) { + return fmt.Errorf("Unknown listener purpose %q", purpose) + } + lnConfig.Purpose[0] = purpose - // Override for now - // TODO: Way to configure - lnConfig.TLSCipherSuites = []uint16{ - // 1.3 - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - tls.TLS_CHACHA20_POLY1305_SHA256, - // 1.2 - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + if lnConfig.TLSCipherSuites == nil { + lnConfig.TLSCipherSuites = []uint16{ + // 1.3 + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + // 1.2 + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + } } lnMux, props, reloadFunc, err := NewListener(lnConfig, b.Logger, ui) @@ -320,9 +323,9 @@ func (b *Server) SetupListeners(ui cli.Ui, config *configutil.SharedConfig, allo } if reloadFunc != nil { - relSlice := b.ReloadFuncs["listener|"+lnConfig.Type] + relSlice := b.ReloadFuncs["listeners"] relSlice = append(relSlice, reloadFunc) - b.ReloadFuncs["listener|"+lnConfig.Type] = relSlice + b.ReloadFuncs["listeners"] = relSlice } if lnConfig.MaxRequestSize == 0 { @@ -708,3 +711,20 @@ func (b *Server) SetupWorkerPublicAddress(conf *config.Config, flagValue string) conf.Worker.PublicAddr = net.JoinHostPort(host, port) return nil } + +// MakeSighupCh returns a channel that can be used for SIGHUP +// reloading. This channel will send a message for every +// SIGHUP received. +func MakeSighupCh() chan struct{} { + resultCh := make(chan struct{}) + + signalCh := make(chan os.Signal, 4) + signal.Notify(signalCh, syscall.SIGHUP) + go func() { + for { + <-signalCh + resultCh <- struct{}{} + } + }() + return resultCh +} diff --git a/internal/cmd/commands.go b/internal/cmd/commands.go index 40b147cc6..81c544390 100644 --- a/internal/cmd/commands.go +++ b/internal/cmd/commands.go @@ -1,10 +1,6 @@ package cmd import ( - "os" - "os/signal" - "syscall" - "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/cmd/commands/accountscmd" "github.com/hashicorp/boundary/internal/cmd/commands/authenticate" @@ -37,14 +33,14 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) { "server": func() (cli.Command, error) { return &server.Command{ Server: base.NewServer(base.NewCommand(serverCmdUi)), - SighupCh: MakeSighupCh(), + SighupCh: base.MakeSighupCh(), SigUSR2Ch: MakeSigUSR2Ch(), }, nil }, "dev": func() (cli.Command, error) { return &dev.Command{ Server: base.NewServer(base.NewCommand(serverCmdUi)), - SighupCh: MakeSighupCh(), + SighupCh: base.MakeSighupCh(), SigUSR2Ch: MakeSigUSR2Ch(), }, nil }, @@ -767,20 +763,3 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) { }, } } - -// MakeSighupCh returns a channel that can be used for SIGHUP -// reloading. This channel will send a message for every -// SIGHUP received. -func MakeSighupCh() chan struct{} { - resultCh := make(chan struct{}) - - signalCh := make(chan os.Signal, 4) - signal.Notify(signalCh, syscall.SIGHUP) - go func() { - for { - <-signalCh - resultCh <- struct{}{} - } - }() - return resultCh -} diff --git a/internal/cmd/commands/server/listener_reload_test.go b/internal/cmd/commands/server/listener_reload_test.go new file mode 100644 index 000000000..322c7b559 --- /dev/null +++ b/internal/cmd/commands/server/listener_reload_test.go @@ -0,0 +1,163 @@ +// +build !hsm + +// NOTE on the NOTE: This is from Vault, but that doesn't mean it's not valid +// going forward with us. +// +// NOTE: we can't use this with HSM. We can't set testing mode on and it's not +// safe to use env vars since that provides an attack vector in the real world. +package server + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" + "os" + "sync" + "testing" + "time" + + "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +const reloadConfig = ` +disable_mlock = true + +telemetry { + prometheus_retention_time = "24h" + disable_hostname = true +} + +controller { + name = "dev-controller" + description = "A default controller created in dev mode" + database { + url = "%s" + } +} + +kms "aead" { + purpose = "root" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_root" +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_worker-auth" +} + +kms "aead" { + purpose = "recovery" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_recovery" +} + +listener "tcp" { + purpose = "api" + tls_cert_file = "%s/bundle.pem" + tls_key_file = "%s/bundle.pem" + cors_enabled = true + cors_allowed_origins = ["*"] +} + +listener "tcp" { + purpose = "cluster" +} + +listener "tcp" { + purpose = "proxy" +} +` + +func TestServer_ReloadListener(t *testing.T) { + t.Parallel() + require := require.New(t) + wg := &sync.WaitGroup{} + + wd, _ := os.Getwd() + wd += "/test-fixtures/reload/" + + td, err := ioutil.TempDir("", "boundary-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(td) + + controllerKey, workerAuthKey, recoveryKey := config.DevKeyGeneration() + + cmd := testServerCommand(t, controllerKey) + + defer func() { + if cmd.DevDatabaseCleanupFunc != nil { + require.NoError(cmd.DevDatabaseCleanupFunc()) + } + }() + require.NoError(err) + + // Setup initial certs + inBytes, err := ioutil.ReadFile(wd + "bundle1.pem") + require.NoError(err) + require.NoError(ioutil.WriteFile(td+"/bundle.pem", inBytes, 0777)) + + relHcl := fmt.Sprintf(reloadConfig, cmd.DatabaseUrl, controllerKey, workerAuthKey, recoveryKey, td, td) + require.NoError(ioutil.WriteFile(td+"/reload.hcl", []byte(relHcl), 0777)) + + // Populate CA pool + inBytes, _ = ioutil.ReadFile(td + "/bundle.pem") + certPool := x509.NewCertPool() + require.True(certPool.AppendCertsFromPEM(inBytes)) + + wg.Add(1) + args := []string{"-config", td + "/reload.hcl"} + go func() { + defer wg.Done() + if code := cmd.Run(args); code != 0 { + output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() + t.Errorf("got a non-zero exit status: %s", output) + } + }() + + testCertificateSerial := func(serial string) { + conn, err := tls.Dial("tcp", "127.0.0.1:9200", &tls.Config{ + RootCAs: certPool, + }) + require.NoError(err) + defer conn.Close() + + require.NoError(conn.Handshake()) + ser := conn.ConnectionState().PeerCertificates[0].SerialNumber.String() + require.Equal(ser, serial) + } + + select { + case <-cmd.startedCh: + case <-time.After(15 * time.Second): + t.Fatalf("timeout") + } + + testCertificateSerial("142541707881583626546634262782315760343015820827") + + inBytes, err = ioutil.ReadFile(wd + "bundle2.pem") + require.NoError(err) + require.NoError(ioutil.WriteFile(td+"/bundle.pem", inBytes, 0777)) + + cmd.SighupCh <- struct{}{} + select { + case <-cmd.reloadedCh: + case <-time.After(5 * time.Second): + t.Fatalf("timeout") + } + + testCertificateSerial("193080739105342897219784862820114567438786419504") + + close(cmd.ShutdownCh) + + wg.Wait() +} diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index ab5810887..b20f009b5 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -25,6 +25,7 @@ import ( "github.com/hashicorp/vault/sdk/helper/mlock" "github.com/mitchellh/cli" "github.com/posener/complete" + "go.uber.org/atomic" ) var ( @@ -35,10 +36,8 @@ var ( type Command struct { *base.Server - ExtShutdownCh chan struct{} - SighupCh chan struct{} - ReloadedCh chan struct{} - SigUSR2Ch chan struct{} + SighupCh chan struct{} + SigUSR2Ch chan struct{} Config *config.Config controller *controller.Controller @@ -51,6 +50,14 @@ type Command struct { flagLogLevel string flagLogFormat string flagCombineLogs bool + + reloadedCh chan struct{} // for tests + startedCh chan struct{} // for tests + presetConfig *atomic.String // for tests + // for tests -- Prometheus seems to use a global collector so if package + // tests are run it errors out even if they're not run in parallel 🙄 cause + // Go runs the tests within the same overall process + skipMetrics bool } func (c *Command) Synopsis() string { @@ -145,9 +152,11 @@ func (c *Command) Run(args []string) int { base.StartMemProfiler(c.Logger) - if err := c.SetupMetrics(c.UI, c.Config.Telemetry); err != nil { - c.UI.Error(err.Error()) - return 1 + if !c.skipMetrics { + if err := c.SetupMetrics(c.UI, c.Config.Telemetry); err != nil { + c.UI.Error(err.Error()) + return 1 + } } if err := c.SetupKMSes(c.UI, c.Config); err != nil { @@ -438,6 +447,11 @@ func (c *Command) Run(args []string) int { } } + // Inform any tests that the server is ready + if c.startedCh != nil { + close(c.startedCh) + } + return c.WaitForInterrupt() } @@ -451,29 +465,37 @@ func (c *Command) ParseFlagsAndConfig(args []string) int { return 1 } - wrapperPath := c.flagConfig - if c.flagConfigKms != "" { - wrapperPath = c.flagConfigKms - } - wrapper, err := wrapper.GetWrapperFromPath(wrapperPath, "config") - if err != nil { - c.UI.Error(err.Error()) - return 1 - } - if wrapper != nil { - c.configWrapper = wrapper - if err := wrapper.Init(c.Context); err != nil { - c.UI.Error(fmt.Errorf("Could not initialize kms: %w", err).Error()) - return 1 - } - } - - if len(c.flagConfig) == 0 { + if len(c.flagConfig) == 0 && c.presetConfig == nil { c.UI.Error("Must specify a config file using -config") return 1 } - c.Config, err = config.LoadFile(c.flagConfig, wrapper) + switch { + case c.presetConfig != nil: + c.Config, err = config.Parse(c.presetConfig.Load()) + + default: + wrapperPath := c.flagConfig + if c.flagConfigKms != "" { + wrapperPath = c.flagConfigKms + } + var configWrapper wrapping.Wrapper + if wrapperPath != "" { + configWrapper, err = wrapper.GetWrapperFromPath(wrapperPath, "config") + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + if configWrapper != nil { + c.configWrapper = configWrapper + if err := configWrapper.Init(c.Context); err != nil { + c.UI.Error(fmt.Errorf("Could not initialize kms: %w", err).Error()) + return 1 + } + } + } + c.Config, err = config.LoadFile(c.flagConfig, configWrapper) + } if err != nil { c.UI.Error("Error parsing config: " + err.Error()) return 1 @@ -547,14 +569,9 @@ func (c *Command) WaitForInterrupt() int { // Wait for shutdown shutdownTriggered := false - shutdownCh := c.ShutdownCh - if c.ExtShutdownCh != nil { - shutdownCh = c.ExtShutdownCh - } - for !shutdownTriggered { select { - case <-shutdownCh: + case <-c.ShutdownCh: c.UI.Output("==> Boundary server shutdown triggered") if c.Config.Worker != nil { @@ -579,11 +596,15 @@ func (c *Command) WaitForInterrupt() int { var err error var newConf *config.Config - if c.flagConfig == "" { + if c.flagConfig == "" && c.presetConfig == nil { goto RUNRELOADFUNCS } - newConf, err = config.LoadFile(c.flagConfig, c.configWrapper) + if c.presetConfig != nil { + newConf, err = config.Parse(c.presetConfig.Load()) + } else { + newConf, err = config.LoadFile(c.flagConfig, c.configWrapper) + } if err != nil { c.Logger.Error("could not reload config", "path", c.flagConfig, "error", err) goto RUNRELOADFUNCS @@ -616,8 +637,8 @@ func (c *Command) WaitForInterrupt() int { } RUNRELOADFUNCS: - if err := c.Reload(); err != nil { - c.UI.Error(fmt.Errorf("Error(s) were encountered during server reload: %w", err).Error()) + if err := c.Reload(newConf); err != nil { + c.UI.Error(fmt.Errorf("Error(s) were encountered during reload: %w", err).Error()) } case <-c.SigUSR2Ch: @@ -630,30 +651,31 @@ func (c *Command) WaitForInterrupt() int { return 0 } -func (c *Command) Reload() error { +func (c *Command) Reload(newConf *config.Config) error { c.ReloadFuncsLock.RLock() defer c.ReloadFuncsLock.RUnlock() var reloadErrors *multierror.Error - for k, relFuncs := range c.ReloadFuncs { - switch { - case strings.HasPrefix(k, "listener|"): - for _, relFunc := range relFuncs { - if relFunc != nil { - if err := relFunc(); err != nil { - reloadErrors = multierror.Append(reloadErrors, fmt.Errorf("error encountered reloading listener: %w", err)) - } - } + for _, relFunc := range c.ReloadFuncs["listeners"] { + if relFunc != nil { + if err := relFunc(); err != nil { + reloadErrors = multierror.Append(reloadErrors, fmt.Errorf("error encountered reloading listener: %w", err)) } } } + if newConf != nil && c.worker != nil { + c.worker.ParseAndStoreTags(newConf.Worker.Tags) + } + // Send a message that we reloaded. This prevents "guessing" sleep times // in tests. - select { - case c.ReloadedCh <- struct{}{}: - default: + if c.reloadedCh != nil { + select { + case c.reloadedCh <- struct{}{}: + default: + } } return reloadErrors.ErrorOrNil() diff --git a/internal/cmd/commands/server/server_test.go b/internal/cmd/commands/server/server_test.go new file mode 100644 index 000000000..500efde12 --- /dev/null +++ b/internal/cmd/commands/server/server_test.go @@ -0,0 +1,48 @@ +package server + +import ( + "fmt" + "testing" + + "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +const rootKmsConfig = ` +kms "aead" { + purpose = "root" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_root" +}` + +func testServerCommand(t *testing.T, controllerKey string) *Command { + require := require.New(t) + t.Helper() + cmd := &Command{ + Server: base.NewServer(base.NewCommand(cli.NewMockUi())), + SighupCh: base.MakeSighupCh(), + startedCh: make(chan struct{}), + reloadedCh: make(chan struct{}, 5), + skipMetrics: true, + } + + require.NoError(cmd.SetupLogging("trace", "", "", "")) + + kmsHcl := fmt.Sprintf(rootKmsConfig, controllerKey) + parsedKmsConfig, err := config.Parse(kmsHcl) + require.NoError(err) + require.NoError(cmd.SetupKMSes(cmd.UI, parsedKmsConfig)) + + err = cmd.CreateDevDatabase(cmd.Context, "postgres") + if err != nil { + if cmd.DevDatabaseCleanupFunc != nil { + require.NoError(cmd.DevDatabaseCleanupFunc()) + } + require.NoError(err) + } + + return cmd +} diff --git a/internal/cmd/commands/server/test-fixtures/reload/bundle1.pem b/internal/cmd/commands/server/test-fixtures/reload/bundle1.pem new file mode 100644 index 000000000..83307f681 --- /dev/null +++ b/internal/cmd/commands/server/test-fixtures/reload/bundle1.pem @@ -0,0 +1,87 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA6xABm4SRwtOZMYMulP1rOOmTSxz6j7TBgpDEk6NqEf9K1XL6 +VQhACAKf0IJbBGtlKcX6MA5xzIZSzBrarujRYRMX4bM5qNqXYa8c9L9q+fhjeV+y +rTINalWnuh5+K9Aw63qPO5dW7ZYsU/R/ZatCxngvA4GB/bufZh9XfE13/o2HP64q +r2ljMz+mhM/e77K39c3H27C/co3q9wa6GLHL+4njwMZcIVPFk7uXoku0PpPEkl3h +rgrLux+XoHQIbojllcqEIth3X1twIROm+eMh0XL0Fo+WKLvO1U3KLQF1AP/Fe7h8 +jcqLGkMC6BhCVxmaGf8PazDyR0K3kAEGHgvHFwIDAQABAoIBAQCFMVGn3It3WMzS +OGHZvGrYGcoDYs07RpHruLoaahs9TWoK3paoPf+CSnJiBKssKupsrCiiuFyVJnud ++Y12VKfnmJkMo7CFVC85A6+lox0rvSooaShmaRke6qAanxKhItvFYnHss0lnYJOH +kt/pLQyuRwVkuCp/KqQcip/Y6FCY5GTE7ILMi1pFa9hVqtpkXr9KVjONFifHEinM +rKWeEgFvYqIBD1r90xgj8tnce0qUrpwyCEVHH2CQZyj/wLg12HnO8t7E/6A7FwXi +do4Ii0sWZeRx2+SgK0KIE7MgHxnNxvgCEenETB4hVbChXQU+Hbgar03TqTv2yK0A +2MgeeujJAoGBAP+kvXyPbLcf7LLg72FeYZfYLvVCuoHOkOEiHYL1CXZNOXO8VQtJ +4Z0P24WfNyGfmOUDP4UL/eYKQ6ssgT9rcJSDBm0duB88e0PUwbSvdvYypLMrokL1 +5KLTP/wVsQj9DmuMqn7pRbrkUasxjb5BAAc4WNrf8DdhZlaDv5b/IbddAoGBAOtj +60jFvVqs6pTv29R0g4cyln0ltP/GPLB/GekzSAvFKODiW31hhwhnV4+yZs0YGGEj +AeGuE1MKkc5VrEMhmiDx612bL+bk8LmjPZXysnY2h9zH0liqOHyC13eMR3QjGOb+ +aFk3zg5/6gIF7p28seWaleJZjiZPPc9mUTbRTBUDAoGAceHmk7Wk3ZM4M5ump/6O +hUFF8fZO9YKa4d/7u5oDJBNU060DSasY+YnV5hm+Spk5WFPxGQj1i2PpLzj9Ps5S +8aXI2BUUL74Wv2no/N/po9V9r19xwlieCLcI2viiy/lHUjvwu+aZLJ+HjjbeCPIV +3CGK275E2bbnCwVX9SEk2PUCgYEAsGg6nVgsF3d9ek7j5a3IIJtF8tY+dm0/cFpg +tccL2F5Sy254eFeN1jt0gKmHp27GXo3YzCQkMVi7evHz3n+hPc1vwcAavySWT9lJ +v0Waf0NQwKI0PuSa3p1EE0DbD+t5ryu8UhijYXR1kDyX3jja7aLTb0YEZSt/vB4H +AVkLdrcCgYEAq+NN1+aKPbZJatOmj1zn8kMrA0KuG8pMVNubQBlA6o8IF1J6TNkB +s2IE2WLhKpVSqhTpqPBgh2sxOmsDs3syLo6fHpLPB2+56TG4HkgTcpzhVjy/FUuv +TRNTnK5e0UnkB0mI1mQCXoyu777tEtX6B6e8pxiHVEZh0oGkqskuohI= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDRzCCAi+gAwIBAgIUGPfKju2r/0rReB6jpRy+NRzVDhswDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MCAXDTIxMDIyMjIzNDc1MVoYDzIwNTEw +MjIyMTU0ODIwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDrEAGbhJHC05kxgy6U/Ws46ZNLHPqPtMGCkMSTo2oR +/0rVcvpVCEAIAp/QglsEa2UpxfowDnHMhlLMGtqu6NFhExfhszmo2pdhrxz0v2r5 ++GN5X7KtMg1qVae6Hn4r0DDreo87l1btlixT9H9lq0LGeC8DgYH9u59mH1d8TXf+ +jYc/riqvaWMzP6aEz97vsrf1zcfbsL9yjer3BroYscv7iePAxlwhU8WTu5eiS7Q+ +k8SSXeGuCsu7H5egdAhuiOWVyoQi2HdfW3AhE6b54yHRcvQWj5You87VTcotAXUA +/8V7uHyNyosaQwLoGEJXGZoZ/w9rMPJHQreQAQYeC8cXAgMBAAGjgY4wgYswDgYD +VR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV +HQ4EFgQUJ6eWLXRfSpu9bf5NBkL9LcK4s3gwHwYDVR0jBBgwFoAUpoUESIm3Tlju +/UzFlkYY8Hu8TMAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3 +DQEBCwUAA4IBAQCUrHC2TVB5ZLfduppFzgKo/YB3iYAiJ/k+LUKqWYO4lsSva2vs +4gSNuDLKvEnNgnuiGfp7/43DsSwjHXQD4pGOY/7i1DSS+T58rVtJ5HrhYyXOxGph +prtzbpN+2QKUkOC+MX6fqbeBu8nhk3bjDQcDLqqSOKToxNdGcD3Pyk8QnS0uv37Z +yLbnAKhINcEdCXKs9QCjPMlpkfaSm+XK6FKvyq6aNRgbXdzWSwLDTmbbXHxS276k +YFGaSN3bMfrvuLCEpxq+t3OvgZxR6rZWE7xRdJXOCHKOVlMA40ST4GlwV8By7NPN +jgY5VUk+2jrML05bG+GbIIUR1eDsBaRrtlY5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDMTCCAhmgAwIBAgIUaxppPIC88WI7kcFaAE2A/6CpmsowDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MCAXDTIxMDIyMjIzNDU0MloYDzIwNTEw +MjIzMDE0NjEyWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC75epj3j6t72LiHpnEvSEPKSy43uZVtQyuBX7u4Okw +AYyqFPXB1PTtcXNZNO6pDNpTxTTx9NwKfuwRonfTQuDeBQWJdetnMCvO2Jata2Gh +EtrHJE+aOpuWnNOU9qb360kM84SUAKKGZwSINGXKiRg5+OOoxcZ6k6xOYba8HQh+ +MP0VQ3eC9SqtWRNuWM7kvvaS9YEQMlT0NBbLZBD2Oxh2xhQJiWXbwFif5LIcXuRN +K6f5Jc+eW5gXL2GJbIHzEAYWwZYB70vwVJZxRj5ZVtKQtVXSWkkI/Dlbx2t7uIE2 +dxfAoRcUBBxgp/4OXyac++3iV3MVac1JAdOG8iXbXYLdAgMBAAGjeTB3MA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSmhQRIibdOWO79 +TMWWRhjwe7xMwDAfBgNVHSMEGDAWgBTVUAc7emL2spJPGcdPWjffywuptTAUBgNV +HREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBACZV4xcWyA8Tsp+Q +IpzjHXaPqxfbX6tF9GzXRI3drqwf5KRRJ/FBG310cOkIdHwUIqmaeXK8H0IqIm1m +/kSB2MG9bguMLN7aW8erCPQ/A5f0ucERYrqT+vuqnruWstPoF1JhCYvMRLPvhcgc +dUXXr99KA/ONtvnvjf1GdV0ujwECgZZVGuLW+ZxPS48eYJQNHRvxzSdv2lDxZLK4 +PRNXMjlTL2S/uFKou6I83G4oWahLtdG+9Eno4n2UuEIqhwO5rvnDOFk/pO3K0AVT +8L0+UwCARAVSQYV8fWd6hMlQLR0FpMxsDSBw5kHeueln/NxjbL6vIUrRj2Uq5OHN +Zot6haQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDMTCCAhmgAwIBAgIUaxppPIC88WI7kcFaAE2A/6CpmsowDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MCAXDTIxMDIyMjIzNDU0MloYDzIwNTEw +MjIzMDE0NjEyWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC75epj3j6t72LiHpnEvSEPKSy43uZVtQyuBX7u4Okw +AYyqFPXB1PTtcXNZNO6pDNpTxTTx9NwKfuwRonfTQuDeBQWJdetnMCvO2Jata2Gh +EtrHJE+aOpuWnNOU9qb360kM84SUAKKGZwSINGXKiRg5+OOoxcZ6k6xOYba8HQh+ +MP0VQ3eC9SqtWRNuWM7kvvaS9YEQMlT0NBbLZBD2Oxh2xhQJiWXbwFif5LIcXuRN +K6f5Jc+eW5gXL2GJbIHzEAYWwZYB70vwVJZxRj5ZVtKQtVXSWkkI/Dlbx2t7uIE2 +dxfAoRcUBBxgp/4OXyac++3iV3MVac1JAdOG8iXbXYLdAgMBAAGjeTB3MA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSmhQRIibdOWO79 +TMWWRhjwe7xMwDAfBgNVHSMEGDAWgBTVUAc7emL2spJPGcdPWjffywuptTAUBgNV +HREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBACZV4xcWyA8Tsp+Q +IpzjHXaPqxfbX6tF9GzXRI3drqwf5KRRJ/FBG310cOkIdHwUIqmaeXK8H0IqIm1m +/kSB2MG9bguMLN7aW8erCPQ/A5f0ucERYrqT+vuqnruWstPoF1JhCYvMRLPvhcgc +dUXXr99KA/ONtvnvjf1GdV0ujwECgZZVGuLW+ZxPS48eYJQNHRvxzSdv2lDxZLK4 +PRNXMjlTL2S/uFKou6I83G4oWahLtdG+9Eno4n2UuEIqhwO5rvnDOFk/pO3K0AVT +8L0+UwCARAVSQYV8fWd6hMlQLR0FpMxsDSBw5kHeueln/NxjbL6vIUrRj2Uq5OHN +Zot6haQ= +-----END CERTIFICATE----- diff --git a/internal/cmd/commands/server/test-fixtures/reload/bundle2.pem b/internal/cmd/commands/server/test-fixtures/reload/bundle2.pem new file mode 100644 index 000000000..96c5ad6d7 --- /dev/null +++ b/internal/cmd/commands/server/test-fixtures/reload/bundle2.pem @@ -0,0 +1,67 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAnz8qCV/AVyMr0aErfjiVJhNOqWomHEu7AOX6DvlWEs4O2YLY +TheY0k4zAEch7wkfUE+K9yM80c2HwzrR16ve03ak04zEBAZwEn4dkh/hYs2VtIbE +eC1Ya8ZpmarrRJLoEWNt+CvnbY8gIkAhDfP+7J73jVUPiR3E+HOTkLSKpOnseCC3 +kTbaOPZZF8KAcose/uRrxG8FrgrqToLW7zMFUagBSghxrSW2Msn0flyTRh6VIFw4 +eANuz5MOLFmSVFFVpgP58lywn2t32ppfL/yF47J/TqXk3Y1vlldZiB3NlH/WIOU2 +xmkglgaMk2XSXnRESBVm9tUMqwWcnOzG8VQECwIDAQABAoIBAE9G8LRt+KDon33i +0HYr0QR9hCGO+J4JjXUrCEvAEPuXnYjnPKvTz36S84zl3JzVW8Ntde8GmdaQjU/B +zomhxHJdlDzEzSh70/tA0ZPXTysS0b5ngROa73Pn+NZJYopm4CUX7L0pjjLal9K1 +Pj9mArjlgrPXbr6CFXbigsn9NzBVgxSn14nKpvupkzRfOtqlUOEIrD7Q3MUkOno4 +zuMZxxox5DOSmjbSGdE994zhhe7f4++sf4H/7qeL+vOJIKhXaWUXyOElRLIUzGTx +M16aiqhGwR0mPwlxw/WCLSCQX0EHXK8gSuHVSulK+t1NixZcbbXkOuBd7gbWh0yT +vkZWh9ECgYEAxl1qP9Ws+lTz9g6xJAo+m5NR5B42qeH9SEfuN/RUyyaWrKUbi6GJ +WvM+XqLXIKAsQeYv4l3UNl+lnrwBL+gfo84r8OvKJWV6RCZtjKzV+FI8rzwGeu28 +sKDCE3tkReI32VSKWrvTBGk/za5WEmWPGVNvSvG8Sh5WC6artSJtRwcCgYEAzYQZ +iT+0HTNlVxPohKUvuG2tw01roYFgywsvKDNHeoaEy/JZLplA3Hg24k6jAc/5TViF +Ij+p6z9WQru31++fXAeisegQZys959iJ+Tp+IDJ9ofeqyi81d+QxtlPNYhXBG720 +p6Q0Lgtt+BfzY7rBMujVHqLOGvE1+cxYfhbc9d0CgYAAppfNo87Qd2zhdsTgAGSa +MA6JuAun3QTussW2S0fn7rV51YTUnXAM61VeDBy2j6/1e2LW1EX487FgZu9+D73i +1K9SOAPOwZl4FcQwPPTqvqJSVNkUmCkRT0WzuKjojchvHxbhG1Ki5hF+hD7mCo1A +oQRxc3+Roq3XlfFkQ7umCwKBgDb3Nb03hHyq2lfHw1B2vaSd8PNjKX4wlCq5+wrN +bDig8bN6Rc/ovSg6HrO4RHCfpxXArxrR3ChG8FM40Zq3Q+/hOupKHtj4/72adIxr +0H/cAS3oh407wxkltwYEs9Gf793zhvWvPSVzeR35iecKc9Gh5B4lfOpHyR/eP2y5 +wK8hAoGAWDYYV1aMsZ+VB14qt/OZitx9y9FFj83uZiHSPIvQHUS88AhyOTvRIUyr +/cY8bHcTDH7h0EQW/nMJl3b/TrpzBuUA+GrJUShfp7JB/Qw2BSYfphnR4/XckyVj +/U26EPr/pL5sm/gnth/CZVzmTdK2uAoZ6bwYqS6c/I4isgztMAM= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDRzCCAi+gAwIBAgIUIdIKLy1j8a+dy5ldqey8QBbA2zAwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MCAXDTIxMDIyMjIzNTg1OFoYDzIwNTEw +MjIyMTU1OTI4WjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCfPyoJX8BXIyvRoSt+OJUmE06paiYcS7sA5foO+VYS +zg7ZgthOF5jSTjMARyHvCR9QT4r3IzzRzYfDOtHXq97TdqTTjMQEBnASfh2SH+Fi +zZW0hsR4LVhrxmmZqutEkugRY234K+dtjyAiQCEN8/7snveNVQ+JHcT4c5OQtIqk +6ex4ILeRNto49lkXwoByix7+5GvEbwWuCupOgtbvMwVRqAFKCHGtJbYyyfR+XJNG +HpUgXDh4A27Pkw4sWZJUUVWmA/nyXLCfa3faml8v/IXjsn9OpeTdjW+WV1mIHc2U +f9Yg5TbGaSCWBoyTZdJedERIFWb21QyrBZyc7MbxVAQLAgMBAAGjgY4wgYswDgYD +VR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV +HQ4EFgQUFpqSoCLFGcEatR0BOusWP+ZcEfYwHwYDVR0jBBgwFoAUpoUESIm3Tlju +/UzFlkYY8Hu8TMAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3 +DQEBCwUAA4IBAQAYiRoBiUM41YAQXDbp7gFAE9HaOecDT5KQ+tLBBskunWJJg4Pq +2TKVkOrrNziP29oexrqXbMuSqi+jvyjsq76ZNRm0YeYopXQL9f6K2tjVdfMSkMRW +dwcxriTj7IC6OInXalJARpmagpNMcNj5y8XLBfJH+U7ejprTsaXY8tVNsIGG3JAI +vFIjajaStCrYuIHIDehetP+tBB+KAfo/YnTxQWvOE752KlsnevxDIBEwXtqCc4Lm +dUcZdzFsyf711nMdjOCxI9YVRvOOZ4wsc1okNTRYlDRZcByGTd0+o8h50Cx2wTG2 +b6aq8q0R/FVPssTikjUqoC4+BDxntZ3qVRT+ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDMTCCAhmgAwIBAgIUaxppPIC88WI7kcFaAE2A/6CpmsowDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJbG9jYWxob3N0MCAXDTIxMDIyMjIzNDU0MloYDzIwNTEw +MjIzMDE0NjEyWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC75epj3j6t72LiHpnEvSEPKSy43uZVtQyuBX7u4Okw +AYyqFPXB1PTtcXNZNO6pDNpTxTTx9NwKfuwRonfTQuDeBQWJdetnMCvO2Jata2Gh +EtrHJE+aOpuWnNOU9qb360kM84SUAKKGZwSINGXKiRg5+OOoxcZ6k6xOYba8HQh+ +MP0VQ3eC9SqtWRNuWM7kvvaS9YEQMlT0NBbLZBD2Oxh2xhQJiWXbwFif5LIcXuRN +K6f5Jc+eW5gXL2GJbIHzEAYWwZYB70vwVJZxRj5ZVtKQtVXSWkkI/Dlbx2t7uIE2 +dxfAoRcUBBxgp/4OXyac++3iV3MVac1JAdOG8iXbXYLdAgMBAAGjeTB3MA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSmhQRIibdOWO79 +TMWWRhjwe7xMwDAfBgNVHSMEGDAWgBTVUAc7emL2spJPGcdPWjffywuptTAUBgNV +HREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBACZV4xcWyA8Tsp+Q +IpzjHXaPqxfbX6tF9GzXRI3drqwf5KRRJ/FBG310cOkIdHwUIqmaeXK8H0IqIm1m +/kSB2MG9bguMLN7aW8erCPQ/A5f0ucERYrqT+vuqnruWstPoF1JhCYvMRLPvhcgc +dUXXr99KA/ONtvnvjf1GdV0ujwECgZZVGuLW+ZxPS48eYJQNHRvxzSdv2lDxZLK4 +PRNXMjlTL2S/uFKou6I83G4oWahLtdG+9Eno4n2UuEIqhwO5rvnDOFk/pO3K0AVT +8L0+UwCARAVSQYV8fWd6hMlQLR0FpMxsDSBw5kHeueln/NxjbL6vIUrRj2Uq5OHN +Zot6haQ= +-----END CERTIFICATE----- diff --git a/internal/cmd/commands/server/worker_tags_reload_test.go b/internal/cmd/commands/server/worker_tags_reload_test.go new file mode 100644 index 000000000..da20bfc0f --- /dev/null +++ b/internal/cmd/commands/server/worker_tags_reload_test.go @@ -0,0 +1,165 @@ +// +build !hsm + +// NOTE on the NOTE: This is from Vault, but that doesn't mean it's not valid +// going forward with us. +// +// NOTE: we can't use this with HSM. We can't set testing mode on and it's not +// safe to use env vars since that provides an attack vector in the real world. + +package server + +import ( + "fmt" + "sync" + "testing" + "time" + + "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" + "go.uber.org/atomic" +) + +const workerBaseConfig = ` +disable_mlock = true + +telemetry { + prometheus_retention_time = "24h" + disable_hostname = true +} + +controller { + name = "dev-controller" + description = "A default controller created in dev mode" + database { + url = "%s" + } +} + +kms "aead" { + purpose = "root" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_root" +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_worker-auth" +} + +kms "aead" { + purpose = "recovery" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_recovery" +} + +listener "tcp" { + purpose = "api" + address = "127.0.0.1:9203" + tls_disable = true + cors_enabled = true + cors_allowed_origins = ["*"] +} + +listener "tcp" { + purpose = "cluster" + address = "127.0.0.1:9204" +} + +listener "tcp" { + purpose = "proxy" + address = "127.0.0.1:9205" +} + +` + +const tag1Config = ` +worker { + name = "dev-worker" + description = "A default worker created in dev mode" + controllers = ["127.0.0.1:9204"] + tags { + type = ["dev", "local"] + } +} +` + +const tag2Config = ` +worker { + name = "dev-worker" + description = "A default worker created in dev mode" + controllers = ["127.0.0.1:9204"] + tags { + foo = ["bar", "baz"] + } +} +` + +func TestServer_ReloadWorkerTags(t *testing.T) { + t.Parallel() + require := require.New(t) + wg := &sync.WaitGroup{} + + controllerKey, workerAuthKey, recoveryKey := config.DevKeyGeneration() + + cmd := testServerCommand(t, controllerKey) + defer func() { + if cmd.DevDatabaseCleanupFunc != nil { + require.NoError(cmd.DevDatabaseCleanupFunc()) + } + }() + + cmd.presetConfig = atomic.NewString(fmt.Sprintf(workerBaseConfig+tag1Config, cmd.DatabaseUrl, controllerKey, workerAuthKey, recoveryKey)) + + wg.Add(1) + go func() { + defer wg.Done() + if code := cmd.Run(nil); code != 0 { + output := cmd.UI.(*cli.MockUi).ErrorWriter.String() + cmd.UI.(*cli.MockUi).OutputWriter.String() + t.Errorf("got a non-zero exit status: %s", output) + } + }() + + select { + case <-cmd.startedCh: + case <-time.After(15 * time.Second): + t.Fatalf("timeout") + } + + fetchWorkerTags := func(name string, key string, values []string) { + t.Helper() + serversRepo, err := cmd.controller.ServersRepoFn() + require.NoError(err) + tags, err := serversRepo.ListTagsForServers(cmd.Context, []string{name}) + require.NoError(err) + require.Len(tags, 2) + require.Equal(key, tags[0].Key) + require.Equal(values[0], tags[0].Value) + require.Equal(key, tags[1].Key) + require.Equal(values[1], tags[1].Value) + } + + // Give time to populate up to the controller + time.Sleep(10 * time.Second) + fetchWorkerTags("dev-worker", "type", []string{"dev", "local"}) + + cmd.presetConfig.Store(fmt.Sprintf(workerBaseConfig+tag2Config, cmd.DatabaseUrl, controllerKey, workerAuthKey, recoveryKey)) + + cmd.SighupCh <- struct{}{} + select { + case <-cmd.reloadedCh: + case <-time.After(15 * time.Second): + t.Fatalf("timeout") + } + + time.Sleep(10 * time.Second) + fetchWorkerTags("dev-worker", "foo", []string{"bar", "baz"}) + + close(cmd.ShutdownCh) + + wg.Wait() +} diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index f8f8d0f67..71a693c6a 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -145,7 +145,7 @@ func DevWorker() (*Config, error) { return parsed, nil } -func devKeyGeneration() (string, string, string) { +func DevKeyGeneration() (string, string, string) { var numBytes int64 = 96 randBuf := new(bytes.Buffer) n, err := randBuf.ReadFrom(&io.LimitedReader{ @@ -168,7 +168,7 @@ func devKeyGeneration() (string, string, string) { // DevController is a Config that is used for dev mode of Boundary // controllers func DevController() (*Config, error) { - controllerKey, workerAuthKey, recoveryKey := devKeyGeneration() + controllerKey, workerAuthKey, recoveryKey := DevKeyGeneration() hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, recoveryKey) parsed, err := Parse(hclStr) @@ -183,7 +183,7 @@ func DevController() (*Config, error) { } func DevCombined() (*Config, error) { - controllerKey, workerAuthKey, recoveryKey := devKeyGeneration() + controllerKey, workerAuthKey, recoveryKey := DevKeyGeneration() hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, recoveryKey) parsed, err := Parse(hclStr) if err != nil { diff --git a/internal/servers/worker/worker.go b/internal/servers/worker/worker.go index 0ff5858a0..a2ef2aad7 100644 --- a/internal/servers/worker/worker.go +++ b/internal/servers/worker/worker.go @@ -59,8 +59,7 @@ func New(conf *Config) (*Worker, error) { w.lastStatusSuccess.Store((*LastStatusInformation)(nil)) w.controllerResolver.Store((*manual.Resolver)(nil)) - w.parseAndStoreTags(conf.RawConfig.Worker.Tags) - w.updateTags.Store(true) + w.ParseAndStoreTags(conf.RawConfig.Worker.Tags) if conf.SecureRandomReader == nil { conf.SecureRandomReader = rand.Reader @@ -148,7 +147,7 @@ func (w *Worker) Resolver() *manual.Resolver { return raw.(*manual.Resolver) } -func (w *Worker) parseAndStoreTags(incoming map[string][]string) { +func (w *Worker) ParseAndStoreTags(incoming map[string][]string) { if len(incoming) == 0 { w.tags.Store(map[string]*servers.TagValues{}) return @@ -160,4 +159,5 @@ func (w *Worker) parseAndStoreTags(incoming map[string][]string) { } } w.tags.Store(tags) + w.updateTags.Store(true) } diff --git a/website/content/docs/configuration/listener/tcp.mdx b/website/content/docs/configuration/listener/tcp.mdx index f46665712..19db1f997 100644 --- a/website/content/docs/configuration/listener/tcp.mdx +++ b/website/content/docs/configuration/listener/tcp.mdx @@ -63,15 +63,21 @@ allowed. assumes TLS by default, so you must explicitly disable TLS to opt-in to insecure communication. -- `tls_cert_file` `(string: ` – +- `tls_cert_file` `(string: ` – Specifies the path to the certificate for TLS. To configure the listener to use a CA certificate, concatenate the primary certificate and the CA certificate together. The primary certificate should appear first in the - combined file. + combined file. On `SIGHUP`, the path set here _at Boundary startup_ will be + used for reloading the certificate; modifying this value while Boundary is + running will have no effect for `SIGHUP`s. -- `tls_key_file` `(string: ` – - Specifies the path to the private key for the certificate. If the key file - is encrypted, you will be prompted to enter the passphrase on server startup. +- `tls_key_file` `(string: ` – + Specifies the path to the private key for the certificate. If the key file is + encrypted, you will be prompted to enter the passphrase on server startup. The + passphrase must stay the same between key files when reloading your + configuration using `SIGHUP`. On `SIGHUP`, the path set here _at Boundary + startup_ will be used for reloading the certificate; modifying this value + while Boundary is running will have no effect for `SIGHUP`s. - `tls_min_version` `(string: "tls12")` – Specifies the minimum supported version of TLS. Accepted values are "tls10", "tls11", "tls12" or "tls13". diff --git a/website/content/docs/configuration/worker.mdx b/website/content/docs/configuration/worker.mdx index c3409868f..c908456c5 100644 --- a/website/content/docs/configuration/worker.mdx +++ b/website/content/docs/configuration/worker.mdx @@ -32,7 +32,10 @@ worker { - `controllers` - A list of hosts/IP addresses and optionally ports for reaching controllers. The port will default to :9201 if not specified. -- `tags` - A map of key-value pairs where values are an array of strings. Most commonly used for [filtering](/docs/concepts/filtering) targets a worker can proxy via [worker tags](/docs/concepts/filtering/worker-tags). +- `tags` - A map of key-value pairs where values are an array of strings. Most + commonly used for [filtering](/docs/concepts/filtering) targets a worker can + proxy via [worker tags](/docs/concepts/filtering/worker-tags). On `SIGHUP`, the + tags set here will be re-parsed and new values used.. ## KMS Configuration