Add TLS certificate and worker tag reloading on SIGHUP (ICU-1142) (ICU-1143) (#959)
This commit is contained in:
1 parent
64e6053278
commit
4738ceee5d
14 files changed
+677
-107
No files matched your search
+11
-1
@@ -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
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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: <required-if-enabled>` –
|
||||
- `tls_cert_file` `(string: <required-if-enabled, reloads-on-SIGHUP>` –
|
||||
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: <required-if-enabled>` –
|
||||
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: <required-if-enabled, reloads-on-SIGHUP>` –
|
||||
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".
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in new issue
Block a user