Refactoring and the worker is more distinct now (#3)
This commit is contained in:
1 parent
75dc91fdb6
commit
07032f6908
10 files changed
+210
-346
No files matched your search
@@ -12,10 +12,6 @@ import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
memProfilerEnabled = true
|
||||
}
|
||||
|
||||
func StartMemProfiler(logger hclog.Logger) {
|
||||
profileDir := filepath.Join(os.TempDir(), "watchtowerprof")
|
||||
if err := os.MkdirAll(profileDir, 0700); err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -38,9 +39,10 @@ import (
|
||||
)
|
||||
|
||||
type ServerListener struct {
|
||||
Mux *alpnmux.ALPNMux
|
||||
Config *configutil.Listener
|
||||
HTTPServer *http.Server
|
||||
Mux *alpnmux.ALPNMux
|
||||
Config *configutil.Listener
|
||||
HTTPServer *http.Server
|
||||
ALPNListener net.Listener
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
@@ -299,7 +301,6 @@ func (b *Server) SetupListeners(ui cli.Ui, config *configutil.SharedConfig) erro
|
||||
b.InfoKeys = append(b.InfoKeys, key)
|
||||
b.Info[key] = fmt.Sprintf(
|
||||
"%s (%s)", lnConfig.Type, strings.Join(propsList, ", "))
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/hashicorp/vault/sdk/helper/mlock"
|
||||
"github.com/hashicorp/watchtower/globals"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/commands/controller/config"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/config"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
var _ cli.Command = (*Command)(nil)
|
||||
var _ cli.CommandAutocomplete = (*Command)(nil)
|
||||
|
||||
var memProfilerEnabled = false
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
*base.Server
|
||||
@@ -39,7 +37,7 @@ type Command struct {
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
flagDev bool
|
||||
flagDevAdminToken string
|
||||
flagDevAdminPassword string
|
||||
flagDevControllerListenAddr string
|
||||
flagCombineLogs bool
|
||||
}
|
||||
@@ -105,11 +103,11 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-admin-token",
|
||||
Target: &c.flagDevAdminToken,
|
||||
Name: "dev-admin-password",
|
||||
Target: &c.flagDevAdminPassword,
|
||||
Default: "",
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_TOKEN",
|
||||
Usage: "Initial admin token. This only applies when running in \"dev\" " +
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
|
||||
Usage: "Initial admin password. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
@@ -152,9 +150,7 @@ func (c *Command) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
if memProfilerEnabled {
|
||||
base.StartMemProfiler(c.Logger)
|
||||
}
|
||||
base.StartMemProfiler(c.Logger)
|
||||
|
||||
if err := c.SetupMetrics(c.UI, c.Config.Telemetry); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
@@ -171,14 +167,14 @@ func (c *Command) Run(args []string) int {
|
||||
}
|
||||
|
||||
// If mlockall(2) isn't supported, show a warning. We disable this in dev
|
||||
// because it is quite scary to see when first using Vault. We also disable
|
||||
// because it is quite scary to see when first using Watchtower. We also disable
|
||||
// this if the user has explicitly disabled mlock in configuration.
|
||||
if !c.flagDev && !c.Config.DisableMlock && !mlock.Supported() {
|
||||
c.UI.Warn(base.WrapAtLength(
|
||||
"WARNING! mlock is not supported on this system! An mlockall(2)-like " +
|
||||
"syscall to prevent memory from being swapped to disk is not " +
|
||||
"supported on this system. For better security, only run Vault on " +
|
||||
"systems where this call is supported. If you are running Vault " +
|
||||
"supported on this system. For better security, only run Watchtower on " +
|
||||
"systems where this call is supported. If you are running Watchtower" +
|
||||
"in a Docker container, provide the IPC_LOCK cap to the container."))
|
||||
}
|
||||
|
||||
@@ -189,13 +185,13 @@ func (c *Command) Run(args []string) int {
|
||||
|
||||
// Write out the PID to the file now that server has successfully started
|
||||
if err := c.StorePidFile(c.Config.PidFile); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error storing PID: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error storing PID: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if c.flagDev {
|
||||
if err := c.CreateDevDatabase(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating dev database container: %s", err.Error()))
|
||||
c.UI.Error(fmt.Errorf("Error creating dev database container: %s", err.Error()).Error())
|
||||
return 1
|
||||
}
|
||||
c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase)
|
||||
@@ -225,17 +221,13 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
case len(c.flagConfig) == 0:
|
||||
c.UI.Error("Must specify a config file using -config")
|
||||
return 1
|
||||
case c.flagDevAdminToken != "":
|
||||
case c.flagDevAdminPassword != "":
|
||||
c.UI.Warn(base.WrapAtLength(
|
||||
"You cannot specify a custom admin token ID outside of \"dev\" mode. " +
|
||||
"You cannot specify a custom admin password outside of \"dev\" mode. " +
|
||||
"Your request has been ignored."))
|
||||
c.flagDevAdminToken = ""
|
||||
c.flagDevAdminPassword = ""
|
||||
}
|
||||
|
||||
if len(c.flagConfig) == 0 {
|
||||
c.UI.Error("Must supply a config file with -config")
|
||||
return 1
|
||||
}
|
||||
c.Config, err = config.LoadFile(c.flagConfig)
|
||||
if err != nil {
|
||||
c.UI.Error("Error parsing config: " + err.Error())
|
||||
@@ -243,9 +235,9 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
}
|
||||
|
||||
} else {
|
||||
c.Config, err = config.Dev()
|
||||
c.Config, err = config.DevController()
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating dev config: %s", err))
|
||||
c.UI.Error(fmt.Errorf("Error creating dev config: %s", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -267,14 +259,14 @@ func (c *Command) Start() int {
|
||||
// Initialize the core
|
||||
ctlr, err := controller.New(conf)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error initializing controller: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error initializing controller: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := ctlr.Start(); err != nil {
|
||||
c.UI.Error(fmt.Sprint("Error starting controller: %w", err))
|
||||
if err := ctlr.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error with controller shutdown: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
|
||||
}
|
||||
return 1
|
||||
}
|
||||
@@ -288,7 +280,7 @@ func (c *Command) Start() int {
|
||||
c.UI.Output("==> Watchtower controller shutdown triggered")
|
||||
|
||||
if err := ctlr.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error with controller shutdown: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error with controller shutdown: %w", err).Error())
|
||||
}
|
||||
|
||||
shutdownTriggered = true
|
||||
@@ -342,7 +334,7 @@ func (c *Command) Start() int {
|
||||
|
||||
RUNRELOADFUNCS:
|
||||
if err := c.Reload(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error(s) were encountered during controller reload: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error(s) were encountered during controller reload: %w", err).Error())
|
||||
}
|
||||
|
||||
case <-c.SigUSR2Ch:
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
controllercmd "github.com/hashicorp/watchtower/internal/cmd/commands/controller"
|
||||
controllerconfig "github.com/hashicorp/watchtower/internal/cmd/commands/controller/config"
|
||||
workercmd "github.com/hashicorp/watchtower/internal/cmd/commands/worker"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/config"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
@@ -16,8 +17,6 @@ import (
|
||||
var _ cli.Command = (*Command)(nil)
|
||||
var _ cli.CommandAutocomplete = (*Command)(nil)
|
||||
|
||||
var memProfilerEnabled = false
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
*base.Server
|
||||
@@ -34,7 +33,7 @@ type Command struct {
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
flagDev bool
|
||||
flagDevAdminToken string
|
||||
flagDevAdminPassword string
|
||||
flagDevControllerListenAddr string
|
||||
flagCombineLogs bool
|
||||
}
|
||||
@@ -83,11 +82,11 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
f = set.NewFlagSet("Dev Options")
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-admin-token",
|
||||
Target: &c.flagDevAdminToken,
|
||||
Name: "dev-admin-password",
|
||||
Target: &c.flagDevAdminPassword,
|
||||
Default: "",
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_TOKEN",
|
||||
Usage: "Initial admin token. This only applies when running in \"dev\" " +
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_PASSWORD",
|
||||
Usage: "Initial admin password. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
@@ -132,9 +131,9 @@ func (c *Command) Run(args []string) int {
|
||||
|
||||
childShutdownCh := make(chan struct{})
|
||||
|
||||
devControllerConfig, err := controllerconfig.Dev()
|
||||
devConfig, err := config.DevController()
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating controller dev config: %s", err))
|
||||
c.UI.Error(fmt.Errorf("Error creating controller dev config: %s", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -143,29 +142,27 @@ func (c *Command) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
if memProfilerEnabled {
|
||||
base.StartMemProfiler(c.Logger)
|
||||
}
|
||||
base.StartMemProfiler(c.Logger)
|
||||
|
||||
if err := c.SetupMetrics(c.UI, devControllerConfig.Telemetry); err != nil {
|
||||
if err := c.SetupMetrics(c.UI, devConfig.Telemetry); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := c.SetupKMSes(c.UI, devControllerConfig.SharedConfig, 2); err != nil {
|
||||
if err := c.SetupKMSes(c.UI, devConfig.SharedConfig, 2); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// Initialize the listeners
|
||||
if err := c.SetupListeners(c.UI, devControllerConfig.SharedConfig); err != nil {
|
||||
if err := c.SetupListeners(c.UI, devConfig.SharedConfig); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// Write out the PID to the file now that server has successfully started
|
||||
if err := c.StorePidFile(devControllerConfig.PidFile); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error storing PID: %w", err))
|
||||
if err := c.StorePidFile(devConfig.PidFile); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Error storing PID: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -208,7 +205,7 @@ func (c *Command) Run(args []string) int {
|
||||
defer c.RunShutdownFuncs(c.UI)
|
||||
|
||||
if err := c.CreateDevDatabase(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating dev database container: %s", err.Error()))
|
||||
c.UI.Error(fmt.Errorf("Error creating dev database container: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase)
|
||||
@@ -218,7 +215,7 @@ func (c *Command) Run(args []string) int {
|
||||
|
||||
// Instantiate the wait group
|
||||
shutdownWg := &sync.WaitGroup{}
|
||||
shutdownWg.Add(1)
|
||||
shutdownWg.Add(2)
|
||||
controllerSighupCh := make(chan struct{})
|
||||
c.childSighupCh = append(c.childSighupCh, controllerSighupCh)
|
||||
go func() {
|
||||
@@ -228,10 +225,21 @@ func (c *Command) Run(args []string) int {
|
||||
Server: c.Server,
|
||||
ShutdownCh: childShutdownCh,
|
||||
SighupCh: controllerSighupCh,
|
||||
Config: devControllerConfig,
|
||||
Config: devConfig,
|
||||
}
|
||||
devController.Start()
|
||||
}()
|
||||
go func() {
|
||||
defer shutdownWg.Done()
|
||||
devWorker := &workercmd.Command{
|
||||
Command: c.Command,
|
||||
Server: c.Server,
|
||||
ShutdownCh: childShutdownCh,
|
||||
SighupCh: controllerSighupCh,
|
||||
Config: devConfig,
|
||||
}
|
||||
devWorker.Start()
|
||||
}()
|
||||
|
||||
// Wait for shutdown
|
||||
shutdownTriggered := false
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/hashicorp/hcl"
|
||||
"github.com/hashicorp/vault/internalshared/configutil"
|
||||
)
|
||||
|
||||
// Config is the configuration for the watchtower controller
|
||||
type Config struct {
|
||||
*configutil.SharedConfig `hcl:"-"`
|
||||
}
|
||||
|
||||
// Dev is a Config that is used for dev mode of Watchtower
|
||||
func Dev() (*Config, error) {
|
||||
randBuf := new(bytes.Buffer)
|
||||
n, err := randBuf.ReadFrom(&io.LimitedReader{
|
||||
R: rand.Reader,
|
||||
N: 64,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != 64 {
|
||||
return nil, fmt.Errorf("expected to read 64 bytes, read %d", n)
|
||||
}
|
||||
controllerKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[0:32])
|
||||
workerAuthKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[32:64])
|
||||
|
||||
hclStr := `
|
||||
disable_mlock = true
|
||||
|
||||
listener "tcp" {
|
||||
tls_disable = true
|
||||
proxy_protocol_behavior = "allow_authorized"
|
||||
proxy_protocol_authorized_addrs = "127.0.0.1"
|
||||
}
|
||||
|
||||
telemetry {
|
||||
prometheus_retention_time = "24h"
|
||||
disable_hostname = true
|
||||
}
|
||||
`
|
||||
|
||||
hclStr = fmt.Sprintf(hclStr, controllerKey, workerAuthKey)
|
||||
parsed, err := Parse(hclStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing dev config: %w", err)
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func New() *Config {
|
||||
return &Config{
|
||||
SharedConfig: new(configutil.SharedConfig),
|
||||
}
|
||||
}
|
||||
|
||||
// LoadFile loads the configuration from the given file.
|
||||
func LoadFile(path string) (*Config, error) {
|
||||
// Read the file
|
||||
d, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf, err := Parse(string(d))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func Parse(d string) (*Config, error) {
|
||||
obj, err := hcl.Parse(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Nothing to do here right now
|
||||
result := New()
|
||||
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
|
||||
|
||||
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 *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{}{}
|
||||
for k, v := range sharedResult {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/sdk/helper/mlock"
|
||||
"github.com/hashicorp/watchtower/globals"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/commands/worker/config"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/config"
|
||||
"github.com/hashicorp/watchtower/internal/servers/worker"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
@@ -20,8 +19,6 @@ import (
|
||||
var _ cli.Command = (*Command)(nil)
|
||||
var _ cli.CommandAutocomplete = (*Command)(nil)
|
||||
|
||||
var memProfilerEnabled = false
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
*base.Server
|
||||
@@ -39,7 +36,6 @@ type Command struct {
|
||||
flagLogLevel string
|
||||
flagLogFormat string
|
||||
flagDev bool
|
||||
flagDevAdminToken string
|
||||
flagDevWorkerListenAddr string
|
||||
flagCombineLogs bool
|
||||
}
|
||||
@@ -104,15 +100,6 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
"production.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-admin-token",
|
||||
Target: &c.flagDevAdminToken,
|
||||
Default: "",
|
||||
EnvVar: "WATCHTWER_DEV_ADMIN_TOKEN",
|
||||
Usage: "Initial admin token. This only applies when running in \"dev\" " +
|
||||
"mode.",
|
||||
})
|
||||
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "dev-listen-address",
|
||||
Target: &c.flagDevWorkerListenAddr,
|
||||
@@ -152,33 +139,27 @@ func (c *Command) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
if memProfilerEnabled {
|
||||
base.StartMemProfiler(c.Logger)
|
||||
}
|
||||
base.StartMemProfiler(c.Logger)
|
||||
|
||||
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.SharedConfig, 2); err != nil {
|
||||
if err := c.SetupKMSes(c.UI, c.Config.SharedConfig, 1); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if c.Config.DefaultMaxRequestDuration != 0 {
|
||||
globals.DefaultMaxRequestDuration = c.Config.DefaultMaxRequestDuration
|
||||
}
|
||||
|
||||
// If mlockall(2) isn't supported, show a warning. We disable this in dev
|
||||
// because it is quite scary to see when first using Vault. We also disable
|
||||
// because it is quite scary to see when first using Watchtower. We also disable
|
||||
// this if the user has explicitly disabled mlock in configuration.
|
||||
if !c.flagDev && !c.Config.DisableMlock && !mlock.Supported() {
|
||||
c.UI.Warn(base.WrapAtLength(
|
||||
"WARNING! mlock is not supported on this system! An mlockall(2)-like " +
|
||||
"syscall to prevent memory from being swapped to disk is not " +
|
||||
"supported on this system. For better security, only run Vault on " +
|
||||
"systems where this call is supported. If you are running Vault " +
|
||||
"supported on this system. For better security, only run Watchtower on " +
|
||||
"systems where this call is supported. If you are running Watchtower" +
|
||||
"in a Docker container, provide the IPC_LOCK cap to the container."))
|
||||
}
|
||||
|
||||
@@ -189,18 +170,10 @@ func (c *Command) Run(args []string) int {
|
||||
|
||||
// Write out the PID to the file now that server has successfully started
|
||||
if err := c.StorePidFile(c.Config.PidFile); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error storing PID: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error storing PID: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if c.flagDev {
|
||||
if err := c.CreateDevDatabase(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating dev database container: %s", err.Error()))
|
||||
return 1
|
||||
}
|
||||
c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase)
|
||||
}
|
||||
|
||||
defer c.RunShutdownFuncs(c.UI)
|
||||
|
||||
c.PrintInfo(c.UI, "worker")
|
||||
@@ -221,17 +194,6 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
|
||||
// Validation
|
||||
if !c.flagDev {
|
||||
switch {
|
||||
case len(c.flagConfig) == 0:
|
||||
c.UI.Error("Must specify a config file using -config")
|
||||
return 1
|
||||
case c.flagDevAdminToken != "":
|
||||
c.UI.Warn(base.WrapAtLength(
|
||||
"You cannot specify a custom admin token ID outside of \"dev\" mode. " +
|
||||
"Your request has been ignored."))
|
||||
c.flagDevAdminToken = ""
|
||||
}
|
||||
|
||||
if len(c.flagConfig) == 0 {
|
||||
c.UI.Error("Must supply a config file with -config")
|
||||
return 1
|
||||
@@ -243,9 +205,9 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
|
||||
}
|
||||
|
||||
} else {
|
||||
c.Config, err = config.Dev()
|
||||
c.Config, err = config.DevWorker()
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating dev config: %s", err))
|
||||
c.UI.Error(fmt.Errorf("Error creating dev config: %s", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -267,14 +229,14 @@ func (c *Command) Start() int {
|
||||
// Initialize the core
|
||||
wrkr, err := worker.New(conf)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error initializing worker: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error initializing worker: %w", err).Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := wrkr.Start(); err != nil {
|
||||
c.UI.Error(fmt.Sprint("Error starting worker: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error starting worker: %w", err).Error())
|
||||
if err := wrkr.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error with worker shutdown: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error with worker shutdown: %w", err).Error())
|
||||
}
|
||||
return 1
|
||||
}
|
||||
@@ -288,7 +250,7 @@ func (c *Command) Start() int {
|
||||
c.UI.Output("==> Watchtower worker shutdown triggered")
|
||||
|
||||
if err := wrkr.Shutdown(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error with worker shutdown: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error with worker shutdown: %w", err).Error())
|
||||
}
|
||||
|
||||
shutdownTriggered = true
|
||||
@@ -342,7 +304,7 @@ func (c *Command) Start() int {
|
||||
|
||||
RUNRELOADFUNCS:
|
||||
if err := c.Reload(); err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error(s) were encountered during worker reload: %w", err))
|
||||
c.UI.Error(fmt.Errorf("Error(s) were encountered during worker reload: %w", err).Error())
|
||||
}
|
||||
|
||||
case <-c.SigUSR2Ch:
|
||||
|
||||
@@ -12,13 +12,58 @@ import (
|
||||
"github.com/hashicorp/vault/internalshared/configutil"
|
||||
)
|
||||
|
||||
const (
|
||||
devConfig = `
|
||||
disable_mlock = true
|
||||
|
||||
listener "tcp" {
|
||||
tls_disable = true
|
||||
proxy_protocol_behavior = "allow_authorized"
|
||||
proxy_protocol_authorized_addrs = "127.0.0.1"
|
||||
}
|
||||
|
||||
telemetry {
|
||||
prometheus_retention_time = "24h"
|
||||
disable_hostname = true
|
||||
}
|
||||
`
|
||||
|
||||
devControllerExtraConfig = `
|
||||
|
||||
kms "aead" {
|
||||
purpose = "controller"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "worker-auth"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
// Config is the configuration for the watchtower controller
|
||||
type Config struct {
|
||||
*configutil.SharedConfig `hcl:"-"`
|
||||
|
||||
DevController bool `hcl:"-"`
|
||||
}
|
||||
|
||||
// Dev is a Config that is used for dev mode of Watchtower
|
||||
func Dev() (*Config, error) {
|
||||
// DevWorker is a Config that is used for dev mode of Watchtower
|
||||
// workers
|
||||
func DevWorker() (*Config, error) {
|
||||
parsed, err := Parse(devConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing dev config: %w", err)
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
// DevController is a Config that is used for dev mode of Watchtower
|
||||
// controllers
|
||||
func DevController() (*Config, error) {
|
||||
randBuf := new(bytes.Buffer)
|
||||
n, err := randBuf.ReadFrom(&io.LimitedReader{
|
||||
R: rand.Reader,
|
||||
@@ -33,38 +78,12 @@ func Dev() (*Config, error) {
|
||||
controllerKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[0:32])
|
||||
workerAuthKey := base64.StdEncoding.EncodeToString(randBuf.Bytes()[32:64])
|
||||
|
||||
hclStr := `
|
||||
disable_mlock = true
|
||||
|
||||
listener "tcp" {
|
||||
tls_disable = true
|
||||
proxy_protocol_behavior = "allow_authorized"
|
||||
proxy_protocol_authorized_addrs = "127.0.0.1"
|
||||
}
|
||||
|
||||
telemetry {
|
||||
prometheus_retention_time = "24h"
|
||||
disable_hostname = true
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "controller"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
}
|
||||
|
||||
kms "aead" {
|
||||
purpose = "worker-auth"
|
||||
aead_type = "aes-gcm"
|
||||
key = "%s"
|
||||
}
|
||||
`
|
||||
|
||||
hclStr = fmt.Sprintf(hclStr, controllerKey, workerAuthKey)
|
||||
hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey)
|
||||
parsed, err := Parse(hclStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing dev config: %w", err)
|
||||
}
|
||||
parsed.DevController = true
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/commands/controller/config"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/config"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/commands/worker/config"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/config"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
||||
@@ -17,97 +17,92 @@ func (c *Worker) startListeners() error {
|
||||
var retErr *multierror.Error
|
||||
servers := make([]func(), 0, len(c.conf.Listeners))
|
||||
for _, ln := range c.conf.Listeners {
|
||||
handler := c.Handler(HandlerProperties{
|
||||
ListenerConfig: ln.Config,
|
||||
})
|
||||
|
||||
/*
|
||||
// TODO: As I write this Vault's having this code audited, make sure to
|
||||
// port over any recommendations
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
server := &http.Server{
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
IdleTimeout: 5 * time.Minute,
|
||||
ErrorLog: c.conf.Logger.StandardLogger(nil),
|
||||
BaseContext: func(net.Listener) context.Context {
|
||||
return c.baseContext
|
||||
},
|
||||
}
|
||||
ln.HTTPServer = server
|
||||
|
||||
if ln.Config.HTTPReadHeaderTimeout > 0 {
|
||||
server.ReadHeaderTimeout = ln.Config.HTTPReadHeaderTimeout
|
||||
}
|
||||
if ln.Config.HTTPReadTimeout > 0 {
|
||||
server.ReadTimeout = ln.Config.HTTPReadTimeout
|
||||
}
|
||||
if ln.Config.HTTPWriteTimeout > 0 {
|
||||
server.WriteTimeout = ln.Config.HTTPWriteTimeout
|
||||
}
|
||||
if ln.Config.HTTPIdleTimeout > 0 {
|
||||
server.IdleTimeout = ln.Config.HTTPIdleTimeout
|
||||
}
|
||||
|
||||
switch ln.Config.TLSDisable {
|
||||
case true:
|
||||
l := ln.Mux.GetListener(alpnmux.NoProto)
|
||||
if l == nil {
|
||||
retErr = multierror.Append(retErr, errors.New("could not get non-tls listener"))
|
||||
continue
|
||||
}
|
||||
servers = append(servers, func() {
|
||||
go server.Serve(l)
|
||||
switch c.conf.RawConfig.DevController {
|
||||
case false:
|
||||
handler := c.Handler(HandlerProperties{
|
||||
ListenerConfig: ln.Config,
|
||||
})
|
||||
|
||||
default:
|
||||
protos := []string{"", "http/1.1", "h2"}
|
||||
for _, v := range protos {
|
||||
l := ln.Mux.GetListener(v)
|
||||
/*
|
||||
// TODO: As I write this Vault's having this code audited, make sure to
|
||||
// port over any recommendations
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
server := &http.Server{
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
IdleTimeout: 5 * time.Minute,
|
||||
ErrorLog: c.conf.Logger.StandardLogger(nil),
|
||||
BaseContext: func(net.Listener) context.Context {
|
||||
return c.baseContext
|
||||
},
|
||||
}
|
||||
ln.HTTPServer = server
|
||||
|
||||
if ln.Config.HTTPReadHeaderTimeout > 0 {
|
||||
server.ReadHeaderTimeout = ln.Config.HTTPReadHeaderTimeout
|
||||
}
|
||||
if ln.Config.HTTPReadTimeout > 0 {
|
||||
server.ReadTimeout = ln.Config.HTTPReadTimeout
|
||||
}
|
||||
if ln.Config.HTTPWriteTimeout > 0 {
|
||||
server.WriteTimeout = ln.Config.HTTPWriteTimeout
|
||||
}
|
||||
if ln.Config.HTTPIdleTimeout > 0 {
|
||||
server.IdleTimeout = ln.Config.HTTPIdleTimeout
|
||||
}
|
||||
|
||||
switch ln.Config.TLSDisable {
|
||||
case true:
|
||||
l := ln.Mux.GetListener(alpnmux.NoProto)
|
||||
if l == nil {
|
||||
retErr = multierror.Append(retErr, fmt.Errorf("could not get tls proto %q listener", v))
|
||||
retErr = multierror.Append(retErr, errors.New("could not get non-tls listener"))
|
||||
continue
|
||||
}
|
||||
servers = append(servers, func() {
|
||||
go server.Serve(l)
|
||||
})
|
||||
|
||||
default:
|
||||
protos := []string{"", "http/1.1", "h2"}
|
||||
for _, v := range protos {
|
||||
l := ln.Mux.GetListener(v)
|
||||
if l == nil {
|
||||
retErr = multierror.Append(retErr, fmt.Errorf("could not get tls proto %q listener", v))
|
||||
continue
|
||||
}
|
||||
servers = append(servers, func() {
|
||||
go server.Serve(l)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workerTLSConfig, peeringInfo, err := c.workerTLS(workerTLSOpts{
|
||||
Address: ln.Config.Address,
|
||||
Protos: []string{"watchtower-worker-v1"},
|
||||
})
|
||||
if err != nil {
|
||||
retErr = multierror.Append(retErr, fmt.Errorf("error getting TLS configuration: %w", err))
|
||||
continue
|
||||
}
|
||||
l, err := ln.Mux.RegisterProto("watchtower-worker-v1", workerTLSConfig)
|
||||
if err != nil {
|
||||
retErr = multierror.Append(retErr, fmt.Errorf("error getting sub-listener for worker proto: %w", err))
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
|
||||
// TODO: Start listner for real; for now send it to the http server just for testing
|
||||
servers = append(servers, func() {
|
||||
go server.Serve(l)
|
||||
})
|
||||
|
||||
// TODO: Add peering info into database
|
||||
_ = peeringInfo
|
||||
default:
|
||||
if !ln.Config.TLSDisable {
|
||||
l := ln.Mux.GetListener(alpnmux.DefaultProto)
|
||||
if l == nil {
|
||||
retErr = multierror.Append(retErr, fmt.Errorf("could not get tls proto %q listener", alpnmux.DefaultProto))
|
||||
continue
|
||||
}
|
||||
ln.ALPNListener = l
|
||||
// TODO: give this listener to a server to handle ALPN auth
|
||||
}
|
||||
// TODO: Register websocket handler against server on this listener
|
||||
}
|
||||
}
|
||||
|
||||
err := retErr.ErrorOrNil()
|
||||
@@ -125,6 +120,11 @@ func (c *Worker) startListeners() error {
|
||||
func (c *Worker) stopListeners() error {
|
||||
serverWg := new(sync.WaitGroup)
|
||||
for _, ln := range c.conf.Listeners {
|
||||
if c.conf.RawConfig.DevController {
|
||||
// These will get closed by the controller's dev instance
|
||||
continue
|
||||
}
|
||||
|
||||
if ln.HTTPServer == nil {
|
||||
continue
|
||||
}
|
||||
@@ -140,8 +140,16 @@ func (c *Worker) stopListeners() error {
|
||||
|
||||
var retErr *multierror.Error
|
||||
for _, ln := range c.conf.Listeners {
|
||||
if err := ln.Mux.Close(); err != nil {
|
||||
retErr = multierror.Append(retErr, err)
|
||||
if ln.ALPNListener != nil {
|
||||
if err := ln.ALPNListener.Close(); err != nil {
|
||||
retErr = multierror.Append(retErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !c.conf.RawConfig.DevController {
|
||||
if err := ln.Mux.Close(); err != nil {
|
||||
retErr = multierror.Append(retErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return retErr.ErrorOrNil()
|
||||
|
||||
Reference in new issue
Block a user