2018-07-25 02:02:27 +00:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-10-16 00:22:19 +00:00
|
|
|
"crypto/tls"
|
2019-02-28 22:29:28 +00:00
|
|
|
"flag"
|
2018-07-25 02:02:27 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2021-03-03 22:01:33 +00:00
|
|
|
"io/ioutil"
|
2019-02-15 01:10:36 +00:00
|
|
|
"net"
|
|
|
|
"net/http"
|
2018-07-25 02:02:27 +00:00
|
|
|
"os"
|
2021-03-03 22:01:33 +00:00
|
|
|
"path/filepath"
|
2018-07-25 02:02:27 +00:00
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2019-02-21 22:53:34 +00:00
|
|
|
"time"
|
2018-07-25 02:02:27 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/sink/inmem"
|
|
|
|
|
2022-08-29 12:18:47 +00:00
|
|
|
systemd "github.com/coreos/go-systemd/daemon"
|
2018-07-25 02:02:27 +00:00
|
|
|
log "github.com/hashicorp/go-hclog"
|
2021-07-16 00:17:31 +00:00
|
|
|
"github.com/hashicorp/go-secure-stdlib/gatedwriter"
|
2022-11-29 14:07:04 +00:00
|
|
|
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
2019-02-19 21:53:29 +00:00
|
|
|
"github.com/hashicorp/vault/api"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth"
|
2018-09-05 15:56:30 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/alicloud"
|
2018-10-30 16:17:19 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/approle"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/aws"
|
|
|
|
"github.com/hashicorp/vault/command/agent/auth/azure"
|
2019-05-06 14:39:28 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/cert"
|
2019-08-26 16:55:08 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/cf"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/gcp"
|
|
|
|
"github.com/hashicorp/vault/command/agent/auth/jwt"
|
2020-01-09 22:56:34 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/kerberos"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/auth/kubernetes"
|
2019-02-15 01:10:36 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/cache"
|
2021-03-03 22:01:33 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/cache/cacheboltdb"
|
|
|
|
"github.com/hashicorp/vault/command/agent/cache/cachememdb"
|
|
|
|
"github.com/hashicorp/vault/command/agent/cache/keymanager"
|
2019-10-11 22:56:07 +00:00
|
|
|
agentConfig "github.com/hashicorp/vault/command/agent/config"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/sink"
|
|
|
|
"github.com/hashicorp/vault/command/agent/sink/file"
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/template"
|
2020-11-23 22:24:32 +00:00
|
|
|
"github.com/hashicorp/vault/command/agent/winsvc"
|
2022-11-11 10:59:16 +00:00
|
|
|
"github.com/hashicorp/vault/helper/logging"
|
2022-02-18 01:10:26 +00:00
|
|
|
"github.com/hashicorp/vault/helper/metricsutil"
|
2021-10-16 00:22:19 +00:00
|
|
|
"github.com/hashicorp/vault/internalshared/configutil"
|
|
|
|
"github.com/hashicorp/vault/internalshared/listenerutil"
|
2019-04-13 07:44:06 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
2022-02-18 01:10:26 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/useragent"
|
2019-10-11 22:56:07 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/version"
|
2019-02-21 22:53:34 +00:00
|
|
|
"github.com/kr/pretty"
|
|
|
|
"github.com/mitchellh/cli"
|
2020-09-30 01:03:09 +00:00
|
|
|
"github.com/oklog/run"
|
2019-02-21 22:53:34 +00:00
|
|
|
"github.com/posener/complete"
|
2021-10-16 00:22:19 +00:00
|
|
|
"google.golang.org/grpc/test/bufconn"
|
2018-07-25 02:02:27 +00:00
|
|
|
)
|
|
|
|
|
2021-04-08 16:43:39 +00:00
|
|
|
var (
|
|
|
|
_ cli.Command = (*AgentCommand)(nil)
|
|
|
|
_ cli.CommandAutocomplete = (*AgentCommand)(nil)
|
|
|
|
)
|
2018-07-25 02:02:27 +00:00
|
|
|
|
2022-11-11 10:59:16 +00:00
|
|
|
const (
|
|
|
|
// flagNameAgentExitAfterAuth is used as an Agent specific flag to indicate
|
|
|
|
// that agent should exit after a single successful auth
|
|
|
|
flagNameAgentExitAfterAuth = "exit-after-auth"
|
|
|
|
)
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
type AgentCommand struct {
|
|
|
|
*BaseCommand
|
2022-11-29 14:07:04 +00:00
|
|
|
logFlags logFlags
|
2018-07-25 02:02:27 +00:00
|
|
|
|
|
|
|
ShutdownCh chan struct{}
|
|
|
|
SighupCh chan struct{}
|
|
|
|
|
|
|
|
logWriter io.Writer
|
|
|
|
logGate *gatedwriter.Writer
|
|
|
|
logger log.Logger
|
|
|
|
|
2022-02-18 01:10:26 +00:00
|
|
|
// Telemetry object
|
|
|
|
metricsHelper *metricsutil.MetricsHelper
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
cleanupGuard sync.Once
|
|
|
|
|
|
|
|
startedCh chan (struct{}) // for tests
|
|
|
|
|
2022-11-29 14:07:04 +00:00
|
|
|
flagConfigs []string
|
|
|
|
flagExitAfterAuth bool
|
2018-07-25 02:02:27 +00:00
|
|
|
flagTestVerifyOnly bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) Synopsis() string {
|
|
|
|
return "Start a Vault agent"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) Help() string {
|
|
|
|
helpText := `
|
|
|
|
Usage: vault agent [options]
|
|
|
|
|
|
|
|
This command starts a Vault agent that can perform automatic authentication
|
|
|
|
in certain environments.
|
|
|
|
|
|
|
|
Start an agent with a configuration file:
|
|
|
|
|
|
|
|
$ vault agent -config=/etc/vault/config.hcl
|
|
|
|
|
|
|
|
For a full list of examples, please see the documentation.
|
|
|
|
|
|
|
|
` + c.Flags().Help()
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) Flags() *FlagSets {
|
|
|
|
set := c.flagSet(FlagSetHTTP)
|
|
|
|
|
|
|
|
f := set.NewFlagSet("Command Options")
|
|
|
|
|
2022-11-29 14:07:04 +00:00
|
|
|
// Augment with the log flags
|
|
|
|
f.addLogFlags(&c.logFlags)
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
f.StringSliceVar(&StringSliceVar{
|
|
|
|
Name: "config",
|
|
|
|
Target: &c.flagConfigs,
|
|
|
|
Completion: complete.PredictOr(
|
|
|
|
complete.PredictFiles("*.hcl"),
|
|
|
|
complete.PredictFiles("*.json"),
|
|
|
|
),
|
|
|
|
Usage: "Path to a configuration file. This configuration file should " +
|
|
|
|
"contain only agent directives.",
|
|
|
|
})
|
|
|
|
|
2019-11-21 22:46:15 +00:00
|
|
|
f.BoolVar(&BoolVar{
|
2022-11-11 10:59:16 +00:00
|
|
|
Name: flagNameAgentExitAfterAuth,
|
2019-11-21 22:46:15 +00:00
|
|
|
Target: &c.flagExitAfterAuth,
|
|
|
|
Default: false,
|
|
|
|
Usage: "If set to true, the agent will exit with code 0 after a single " +
|
|
|
|
"successful auth, where success means that a token was retrieved and " +
|
|
|
|
"all sinks successfully wrote it",
|
|
|
|
})
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
// Internal-only flags to follow.
|
|
|
|
//
|
|
|
|
// Why hello there little source code reader! Welcome to the Vault source
|
|
|
|
// code. The remaining options are intentionally undocumented and come with
|
2019-03-19 13:32:45 +00:00
|
|
|
// no warranty or backwards-compatibility promise. Do not use these flags
|
2018-07-25 02:02:27 +00:00
|
|
|
// in production. Do not build automation using these flags. Unless you are
|
|
|
|
// developing against Vault, you should not need any of these flags.
|
|
|
|
f.BoolVar(&BoolVar{
|
|
|
|
Name: "test-verify-only",
|
|
|
|
Target: &c.flagTestVerifyOnly,
|
|
|
|
Default: false,
|
|
|
|
Hidden: true,
|
|
|
|
})
|
|
|
|
|
|
|
|
// End internal-only flags.
|
|
|
|
|
|
|
|
return set
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) AutocompleteArgs() complete.Predictor {
|
|
|
|
return complete.PredictNothing
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) AutocompleteFlags() complete.Flags {
|
|
|
|
return c.Flags().Completions()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) Run(args []string) int {
|
|
|
|
f := c.Flags()
|
|
|
|
|
|
|
|
if err := f.Parse(args); err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a logger. We wrap it in a gated writer so that it doesn't
|
|
|
|
// start logging too early.
|
2020-01-23 18:57:18 +00:00
|
|
|
c.logGate = gatedwriter.NewWriter(os.Stderr)
|
2018-07-25 02:02:27 +00:00
|
|
|
c.logWriter = c.logGate
|
2022-11-29 14:07:04 +00:00
|
|
|
|
|
|
|
if c.logFlags.flagCombineLogs {
|
2018-07-25 02:02:27 +00:00
|
|
|
c.logWriter = os.Stdout
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validation
|
|
|
|
if len(c.flagConfigs) != 1 {
|
|
|
|
c.UI.Error("Must specify exactly one config path using -config")
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2022-11-11 10:59:16 +00:00
|
|
|
// Load the configuration file
|
2019-10-11 22:56:07 +00:00
|
|
|
config, err := agentConfig.LoadConfig(c.flagConfigs[0])
|
2018-07-25 02:02:27 +00:00
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error loading configuration from %s: %s", c.flagConfigs[0], err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure at least one config was found.
|
|
|
|
if config == nil {
|
|
|
|
c.UI.Output(wrapAtLength(
|
|
|
|
"No configuration read. Please provide the configuration with the " +
|
|
|
|
"-config flag."))
|
|
|
|
return 1
|
|
|
|
}
|
2022-11-11 10:59:16 +00:00
|
|
|
|
2019-03-15 18:58:53 +00:00
|
|
|
if config.AutoAuth == nil && config.Cache == nil {
|
|
|
|
c.UI.Error("No auto_auth or cache block found in config file")
|
2018-07-25 02:02:27 +00:00
|
|
|
return 1
|
|
|
|
}
|
2019-03-15 18:58:53 +00:00
|
|
|
if config.AutoAuth == nil {
|
|
|
|
c.UI.Info("No auto_auth block found in config file, not starting automatic authentication feature")
|
|
|
|
}
|
2018-07-25 02:02:27 +00:00
|
|
|
|
2022-11-29 14:07:04 +00:00
|
|
|
c.updateConfig(f, config)
|
2019-11-21 22:46:15 +00:00
|
|
|
|
2022-11-29 14:07:04 +00:00
|
|
|
// Parse all the log related config
|
2022-11-11 10:59:16 +00:00
|
|
|
logLevel, err := logging.ParseLogLevel(config.LogLevel)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
logFormat, err := logging.ParseLogFormat(config.LogFormat)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2022-11-29 14:07:04 +00:00
|
|
|
logRotateDuration, err := parseutil.ParseDurationSecond(config.LogRotateDuration)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
logRotateBytes, err := parseutil.ParseInt(config.LogRotateBytes)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
logRotateMaxFiles, err := parseutil.ParseInt(config.LogRotateMaxFiles)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
logCfg := &logging.LogConfig{
|
|
|
|
Name: "vault-agent",
|
|
|
|
LogLevel: logLevel,
|
|
|
|
LogFormat: logFormat,
|
|
|
|
LogFilePath: config.LogFile,
|
|
|
|
LogRotateDuration: logRotateDuration,
|
|
|
|
LogRotateBytes: int(logRotateBytes),
|
|
|
|
LogRotateMaxFiles: int(logRotateMaxFiles),
|
|
|
|
}
|
|
|
|
|
2022-11-11 10:59:16 +00:00
|
|
|
l, err := logging.Setup(logCfg, c.logWriter)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(err.Error())
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
c.logger = l
|
2019-02-28 22:29:28 +00:00
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
infoKeys := make([]string, 0, 10)
|
|
|
|
info := make(map[string]string)
|
2022-11-29 14:07:04 +00:00
|
|
|
info["log level"] = config.LogLevel
|
2018-07-25 02:02:27 +00:00
|
|
|
infoKeys = append(infoKeys, "log level")
|
|
|
|
|
|
|
|
infoKeys = append(infoKeys, "version")
|
|
|
|
verInfo := version.GetVersion()
|
|
|
|
info["version"] = verInfo.FullVersionNumber(false)
|
|
|
|
if verInfo.Revision != "" {
|
|
|
|
info["version sha"] = strings.Trim(verInfo.Revision, "'")
|
|
|
|
infoKeys = append(infoKeys, "version sha")
|
|
|
|
}
|
|
|
|
infoKeys = append(infoKeys, "cgo")
|
|
|
|
info["cgo"] = "disabled"
|
|
|
|
if version.CgoEnabled {
|
|
|
|
info["cgo"] = "enabled"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests might not want to start a vault server and just want to verify
|
|
|
|
// the configuration.
|
|
|
|
if c.flagTestVerifyOnly {
|
|
|
|
if os.Getenv("VAULT_TEST_VERIFY_ONLY_DUMP_CONFIG") != "" {
|
|
|
|
c.UI.Output(fmt.Sprintf(
|
|
|
|
"\nConfiguration:\n%s\n",
|
|
|
|
pretty.Sprint(*config)))
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-02-28 22:29:28 +00:00
|
|
|
// Ignore any setting of agent's address. This client is used by the agent
|
|
|
|
// to reach out to Vault. This should never loop back to agent.
|
|
|
|
c.flagAgentAddress = ""
|
2018-07-25 02:02:27 +00:00
|
|
|
client, err := c.Client()
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf(
|
|
|
|
"Error fetching client: %v",
|
|
|
|
err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
// ctx and cancelFunc are passed to the AuthHandler, SinkServer, and
|
|
|
|
// TemplateServer that periodically listen for ctx.Done() to fire and shut
|
|
|
|
// down accordingly.
|
2018-07-25 02:02:27 +00:00
|
|
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
2021-09-30 11:33:14 +00:00
|
|
|
defer cancelFunc()
|
2018-07-25 02:02:27 +00:00
|
|
|
|
2022-02-18 01:10:26 +00:00
|
|
|
// telemetry configuration
|
|
|
|
inmemMetrics, _, prometheusEnabled, err := configutil.SetupTelemetry(&configutil.SetupTelemetryOpts{
|
|
|
|
Config: config.Telemetry,
|
|
|
|
Ui: c.UI,
|
|
|
|
ServiceName: "vault",
|
|
|
|
DisplayName: "Vault",
|
|
|
|
UserAgent: useragent.String(),
|
|
|
|
ClusterName: config.ClusterName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error initializing telemetry: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
c.metricsHelper = metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled)
|
|
|
|
|
2019-03-15 18:58:53 +00:00
|
|
|
var method auth.AuthMethod
|
2018-07-25 02:02:27 +00:00
|
|
|
var sinks []*sink.SinkConfig
|
2022-01-19 17:43:12 +00:00
|
|
|
var templateNamespace string
|
2019-03-15 18:58:53 +00:00
|
|
|
if config.AutoAuth != nil {
|
2022-01-19 17:43:12 +00:00
|
|
|
if client.Headers().Get(consts.NamespaceHeaderName) == "" && config.AutoAuth.Method.Namespace != "" {
|
|
|
|
client.SetNamespace(config.AutoAuth.Method.Namespace)
|
|
|
|
}
|
|
|
|
templateNamespace = client.Headers().Get(consts.NamespaceHeaderName)
|
2022-06-16 22:06:22 +00:00
|
|
|
|
|
|
|
sinkClient, err := client.CloneWithHeaders()
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error cloning client for file sink: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.DisableIdleConnsAutoAuth {
|
|
|
|
sinkClient.SetMaxIdleConnections(-1)
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:59:49 +00:00
|
|
|
if config.DisableKeepAlivesAutoAuth {
|
|
|
|
sinkClient.SetDisableKeepAlives(true)
|
|
|
|
}
|
|
|
|
|
2019-03-15 18:58:53 +00:00
|
|
|
for _, sc := range config.AutoAuth.Sinks {
|
|
|
|
switch sc.Type {
|
|
|
|
case "file":
|
|
|
|
config := &sink.SinkConfig{
|
2020-08-25 21:26:06 +00:00
|
|
|
Logger: c.logger.Named("sink.file"),
|
|
|
|
Config: sc.Config,
|
2022-06-16 22:06:22 +00:00
|
|
|
Client: sinkClient,
|
2020-08-25 21:26:06 +00:00
|
|
|
WrapTTL: sc.WrapTTL,
|
|
|
|
DHType: sc.DHType,
|
2020-08-17 16:36:16 +00:00
|
|
|
DeriveKey: sc.DeriveKey,
|
2020-08-25 21:26:06 +00:00
|
|
|
DHPath: sc.DHPath,
|
|
|
|
AAD: sc.AAD,
|
2019-03-15 18:58:53 +00:00
|
|
|
}
|
|
|
|
s, err := file.NewFileSink(config)
|
|
|
|
if err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
c.UI.Error(fmt.Errorf("Error creating file sink: %w", err).Error())
|
2019-03-15 18:58:53 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
config.Sink = s
|
|
|
|
sinks = append(sinks, config)
|
|
|
|
default:
|
|
|
|
c.UI.Error(fmt.Sprintf("Unknown sink type %q", sc.Type))
|
2018-07-25 02:02:27 +00:00
|
|
|
return 1
|
|
|
|
}
|
2019-03-15 18:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
authConfig := &auth.AuthConfig{
|
|
|
|
Logger: c.logger.Named(fmt.Sprintf("auth.%s", config.AutoAuth.Method.Type)),
|
2022-01-19 17:43:12 +00:00
|
|
|
MountPath: config.AutoAuth.Method.MountPath,
|
2019-03-15 18:58:53 +00:00
|
|
|
Config: config.AutoAuth.Method.Config,
|
|
|
|
}
|
|
|
|
switch config.AutoAuth.Method.Type {
|
|
|
|
case "alicloud":
|
|
|
|
method, err = alicloud.NewAliCloudAuthMethod(authConfig)
|
|
|
|
case "aws":
|
|
|
|
method, err = aws.NewAWSAuthMethod(authConfig)
|
|
|
|
case "azure":
|
|
|
|
method, err = azure.NewAzureAuthMethod(authConfig)
|
2019-05-06 14:39:28 +00:00
|
|
|
case "cert":
|
|
|
|
method, err = cert.NewCertAuthMethod(authConfig)
|
2019-08-26 16:55:08 +00:00
|
|
|
case "cf":
|
|
|
|
method, err = cf.NewCFAuthMethod(authConfig)
|
2019-03-15 18:58:53 +00:00
|
|
|
case "gcp":
|
|
|
|
method, err = gcp.NewGCPAuthMethod(authConfig)
|
|
|
|
case "jwt":
|
|
|
|
method, err = jwt.NewJWTAuthMethod(authConfig)
|
2020-01-09 22:56:34 +00:00
|
|
|
case "kerberos":
|
|
|
|
method, err = kerberos.NewKerberosAuthMethod(authConfig)
|
2019-03-15 18:58:53 +00:00
|
|
|
case "kubernetes":
|
|
|
|
method, err = kubernetes.NewKubernetesAuthMethod(authConfig)
|
|
|
|
case "approle":
|
|
|
|
method, err = approle.NewApproleAuthMethod(authConfig)
|
2019-08-26 16:55:08 +00:00
|
|
|
case "pcf": // Deprecated.
|
|
|
|
method, err = cf.NewCFAuthMethod(authConfig)
|
2018-07-25 02:02:27 +00:00
|
|
|
default:
|
2019-03-15 18:58:53 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Unknown auth method %q", config.AutoAuth.Method.Type))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
c.UI.Error(fmt.Errorf("Error creating %s auth method: %w", config.AutoAuth.Method.Type, err).Error())
|
2018-07-25 02:02:27 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 18:14:09 +00:00
|
|
|
// We do this after auto-auth has been configured, because we don't want to
|
|
|
|
// confuse the issue of retries for auth failures which have their own
|
|
|
|
// config and are handled a bit differently.
|
|
|
|
if os.Getenv(api.EnvVaultMaxRetries) == "" {
|
|
|
|
client.SetMaxRetries(config.Vault.Retry.NumRetries)
|
|
|
|
}
|
|
|
|
|
2021-02-24 11:58:10 +00:00
|
|
|
enforceConsistency := cache.EnforceConsistencyNever
|
|
|
|
whenInconsistent := cache.WhenInconsistentFail
|
2022-12-05 15:51:03 +00:00
|
|
|
if config.APIProxy != nil {
|
|
|
|
switch config.APIProxy.EnforceConsistency {
|
|
|
|
case "always":
|
|
|
|
enforceConsistency = cache.EnforceConsistencyAlways
|
|
|
|
case "never", "":
|
|
|
|
default:
|
|
|
|
c.UI.Error(fmt.Sprintf("Unknown api_proxy setting for enforce_consistency: %q", config.APIProxy.EnforceConsistency))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
switch config.APIProxy.WhenInconsistent {
|
|
|
|
case "retry":
|
|
|
|
whenInconsistent = cache.WhenInconsistentRetry
|
|
|
|
case "forward":
|
|
|
|
whenInconsistent = cache.WhenInconsistentForward
|
|
|
|
case "fail", "":
|
|
|
|
default:
|
|
|
|
c.UI.Error(fmt.Sprintf("Unknown api_proxy setting for when_inconsistent: %q", config.APIProxy.WhenInconsistent))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Keep Cache configuration for legacy reasons, but error if defined alongside API Proxy
|
2021-02-24 11:58:10 +00:00
|
|
|
if config.Cache != nil {
|
|
|
|
switch config.Cache.EnforceConsistency {
|
|
|
|
case "always":
|
2022-12-05 15:51:03 +00:00
|
|
|
if enforceConsistency != cache.EnforceConsistencyNever {
|
|
|
|
c.UI.Error("enforce_consistency configured in both api_proxy and cache blocks. Please remove this configuration from the cache block.")
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
enforceConsistency = cache.EnforceConsistencyAlways
|
|
|
|
}
|
2021-02-24 11:58:10 +00:00
|
|
|
case "never", "":
|
|
|
|
default:
|
|
|
|
c.UI.Error(fmt.Sprintf("Unknown cache setting for enforce_consistency: %q", config.Cache.EnforceConsistency))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
switch config.Cache.WhenInconsistent {
|
|
|
|
case "retry":
|
2022-12-05 15:51:03 +00:00
|
|
|
if whenInconsistent != cache.WhenInconsistentFail {
|
|
|
|
c.UI.Error("when_inconsistent configured in both api_proxy and cache blocks. Please remove this configuration from the cache block.")
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
whenInconsistent = cache.WhenInconsistentRetry
|
|
|
|
}
|
2021-02-24 11:58:10 +00:00
|
|
|
case "forward":
|
2022-12-05 15:51:03 +00:00
|
|
|
if whenInconsistent != cache.WhenInconsistentFail {
|
|
|
|
c.UI.Error("when_inconsistent configured in both api_proxy and cache blocks. Please remove this configuration from the cache block.")
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
whenInconsistent = cache.WhenInconsistentForward
|
|
|
|
}
|
2021-02-24 11:58:10 +00:00
|
|
|
case "fail", "":
|
|
|
|
default:
|
|
|
|
c.UI.Error(fmt.Sprintf("Unknown cache setting for when_inconsistent: %q", config.Cache.WhenInconsistent))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-25 21:26:06 +00:00
|
|
|
// Warn if cache _and_ cert auto-auth is enabled but certificates were not
|
|
|
|
// provided in the auto_auth.method["cert"].config stanza.
|
|
|
|
if config.Cache != nil && (config.AutoAuth != nil && config.AutoAuth.Method != nil && config.AutoAuth.Method.Type == "cert") {
|
|
|
|
_, okCertFile := config.AutoAuth.Method.Config["client_cert"]
|
|
|
|
_, okCertKey := config.AutoAuth.Method.Config["client_key"]
|
|
|
|
|
|
|
|
// If neither of these exists in the cert stanza, agent will use the
|
|
|
|
// certs from the vault stanza.
|
|
|
|
if !okCertFile && !okCertKey {
|
|
|
|
c.UI.Warn(wrapAtLength("WARNING! Cache is enabled and using the same certificates " +
|
|
|
|
"from the 'cert' auto-auth method specified in the 'vault' stanza. Consider " +
|
|
|
|
"specifying certificate information in the 'cert' auto-auth's config stanza."))
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output the header that the agent has started
|
2022-11-29 14:07:04 +00:00
|
|
|
if !c.logFlags.flagCombineLogs {
|
2020-08-25 21:26:06 +00:00
|
|
|
c.UI.Output("==> Vault agent started! Log data will stream in below:\n")
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 22:01:33 +00:00
|
|
|
var leaseCache *cache.LeaseCache
|
|
|
|
var previousToken string
|
2019-02-15 01:10:36 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
proxyClient, err := client.CloneWithHeaders()
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error cloning client for proxying: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
2022-06-16 22:06:22 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
if config.DisableIdleConnsAPIProxy {
|
|
|
|
proxyClient.SetMaxIdleConnections(-1)
|
|
|
|
}
|
2022-06-16 22:06:22 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
if config.DisableKeepAlivesAPIProxy {
|
|
|
|
proxyClient.SetDisableKeepAlives(true)
|
|
|
|
}
|
2022-07-28 19:59:49 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
apiProxyLogger := c.logger.Named("apiproxy")
|
|
|
|
|
|
|
|
// The API proxy to be used, if listeners are configured
|
|
|
|
apiProxy, err := cache.NewAPIProxy(&cache.APIProxyConfig{
|
|
|
|
Client: proxyClient,
|
|
|
|
Logger: apiProxyLogger,
|
|
|
|
EnforceConsistency: enforceConsistency,
|
|
|
|
WhenInconsistentAction: whenInconsistent,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error creating API proxy: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse agent cache configurations
|
|
|
|
if config.Cache != nil {
|
|
|
|
cacheLogger := c.logger.Named("cache")
|
2019-02-15 01:10:36 +00:00
|
|
|
|
|
|
|
// Create the lease cache proxier and set its underlying proxier to
|
|
|
|
// the API proxier.
|
2021-03-03 22:01:33 +00:00
|
|
|
leaseCache, err = cache.NewLeaseCache(&cache.LeaseCacheConfig{
|
2022-06-16 22:06:22 +00:00
|
|
|
Client: proxyClient,
|
2019-02-15 01:10:36 +00:00
|
|
|
BaseContext: ctx,
|
|
|
|
Proxier: apiProxy,
|
|
|
|
Logger: cacheLogger.Named("leasecache"),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error creating lease cache: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2021-03-03 22:01:33 +00:00
|
|
|
// Configure persistent storage and add to LeaseCache
|
|
|
|
if config.Cache.Persist != nil {
|
|
|
|
if config.Cache.Persist.Path == "" {
|
|
|
|
c.UI.Error("must specify persistent cache path")
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set AAD based on key protection type
|
|
|
|
var aad string
|
|
|
|
switch config.Cache.Persist.Type {
|
|
|
|
case "kubernetes":
|
|
|
|
aad, err = getServiceAccountJWT(config.Cache.Persist.ServiceAccountTokenFile)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("failed to read service account token from %s: %s", config.Cache.Persist.ServiceAccountTokenFile, err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
c.UI.Error(fmt.Sprintf("persistent key protection type %q not supported", config.Cache.Persist.Type))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if bolt file exists already
|
|
|
|
dbFileExists, err := cacheboltdb.DBFileExists(config.Cache.Persist.Path)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("failed to check if bolt file exists at path %s: %s", config.Cache.Persist.Path, err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if dbFileExists {
|
|
|
|
// Open the bolt file, but wait to setup Encryption
|
|
|
|
ps, err := cacheboltdb.NewBoltStorage(&cacheboltdb.BoltStorageConfig{
|
|
|
|
Path: config.Cache.Persist.Path,
|
|
|
|
Logger: cacheLogger.Named("cacheboltdb"),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error opening persistent cache: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the token from bolt for retrieving the encryption key,
|
|
|
|
// then setup encryption so that restore is possible
|
|
|
|
token, err := ps.GetRetrievalToken()
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error getting retrieval token from persistent cache: %v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ps.Close(); err != nil {
|
|
|
|
c.UI.Warn(fmt.Sprintf("Failed to close persistent cache file after getting retrieval token: %s", err))
|
|
|
|
}
|
|
|
|
|
2022-08-23 19:37:16 +00:00
|
|
|
km, err := keymanager.NewPassthroughKeyManager(ctx, token)
|
2021-03-03 22:01:33 +00:00
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("failed to configure persistence encryption for cache: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open the bolt file with the wrapper provided
|
|
|
|
ps, err = cacheboltdb.NewBoltStorage(&cacheboltdb.BoltStorageConfig{
|
|
|
|
Path: config.Cache.Persist.Path,
|
|
|
|
Logger: cacheLogger.Named("cacheboltdb"),
|
|
|
|
Wrapper: km.Wrapper(),
|
|
|
|
AAD: aad,
|
|
|
|
})
|
|
|
|
if err != nil {
|
2021-12-08 18:32:49 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Error opening persistent cache with wrapper: %v", err))
|
2021-03-03 22:01:33 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore anything in the persistent cache to the memory cache
|
|
|
|
if err := leaseCache.Restore(ctx, ps); err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error restoring in-memory cache from persisted file: %v", err))
|
|
|
|
if config.Cache.Persist.ExitOnErr {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cacheLogger.Info("loaded memcache from persistent storage")
|
|
|
|
|
|
|
|
// Check for previous auto-auth token
|
|
|
|
oldTokenBytes, err := ps.GetAutoAuthToken(ctx)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error in fetching previous auto-auth token: %s", err))
|
|
|
|
if config.Cache.Persist.ExitOnErr {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(oldTokenBytes) > 0 {
|
|
|
|
oldToken, err := cachememdb.Deserialize(oldTokenBytes)
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error in deserializing previous auto-auth token cache entry: %s", err))
|
|
|
|
if config.Cache.Persist.ExitOnErr {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
previousToken = oldToken.Token
|
|
|
|
}
|
|
|
|
|
|
|
|
// If keep_after_import true, set persistent storage layer in
|
|
|
|
// leaseCache, else remove db file
|
|
|
|
if config.Cache.Persist.KeepAfterImport {
|
|
|
|
defer ps.Close()
|
|
|
|
leaseCache.SetPersistentStorage(ps)
|
|
|
|
} else {
|
|
|
|
if err := ps.Close(); err != nil {
|
|
|
|
c.UI.Warn(fmt.Sprintf("failed to close persistent cache file: %s", err))
|
|
|
|
}
|
|
|
|
dbFile := filepath.Join(config.Cache.Persist.Path, cacheboltdb.DatabaseFileName)
|
|
|
|
if err := os.Remove(dbFile); err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("failed to remove persistent storage file %s: %s", dbFile, err))
|
|
|
|
if config.Cache.Persist.ExitOnErr {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2022-08-23 19:37:16 +00:00
|
|
|
km, err := keymanager.NewPassthroughKeyManager(ctx, nil)
|
2021-03-03 22:01:33 +00:00
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("failed to configure persistence encryption for cache: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
ps, err := cacheboltdb.NewBoltStorage(&cacheboltdb.BoltStorageConfig{
|
|
|
|
Path: config.Cache.Persist.Path,
|
|
|
|
Logger: cacheLogger.Named("cacheboltdb"),
|
|
|
|
Wrapper: km.Wrapper(),
|
|
|
|
AAD: aad,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error creating persistent cache: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
cacheLogger.Info("configured persistent storage", "path", config.Cache.Persist.Path)
|
|
|
|
|
|
|
|
// Stash the key material in bolt
|
2022-08-23 19:37:16 +00:00
|
|
|
token, err := km.RetrievalToken(ctx)
|
2021-03-03 22:01:33 +00:00
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error getting persistent key: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if err := ps.StoreRetrievalToken(token); err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error setting key in persistent cache: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
defer ps.Close()
|
|
|
|
leaseCache.SetPersistentStorage(ps)
|
|
|
|
}
|
|
|
|
}
|
2022-12-05 15:51:03 +00:00
|
|
|
}
|
2021-03-03 22:01:33 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
var listeners []net.Listener
|
|
|
|
|
|
|
|
// If there are templates, add an in-process listener
|
|
|
|
if len(config.Templates) > 0 {
|
|
|
|
config.Listeners = append(config.Listeners, &configutil.Listener{Type: listenerutil.BufConnType})
|
|
|
|
}
|
|
|
|
for i, lnConfig := range config.Listeners {
|
|
|
|
var ln net.Listener
|
|
|
|
var tlsConf *tls.Config
|
|
|
|
|
|
|
|
if lnConfig.Type == listenerutil.BufConnType {
|
|
|
|
inProcListener := bufconn.Listen(1024 * 1024)
|
|
|
|
if config.Cache != nil {
|
|
|
|
config.Cache.InProcDialer = listenerutil.NewBufConnWrapper(inProcListener)
|
|
|
|
}
|
|
|
|
ln = inProcListener
|
|
|
|
} else {
|
|
|
|
ln, tlsConf, err = cache.StartListener(lnConfig)
|
2019-02-27 21:14:58 +00:00
|
|
|
if err != nil {
|
2022-12-05 15:51:03 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Error starting listener: %v", err))
|
2019-02-27 21:14:58 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
listeners = append(listeners, ln)
|
2019-02-15 01:10:36 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
proxyVaultToken := true
|
|
|
|
var inmemSink sink.Sink
|
|
|
|
if config.APIProxy != nil {
|
|
|
|
if config.APIProxy.UseAutoAuthToken {
|
|
|
|
apiProxyLogger.Debug("auto-auth token is allowed to be used; configuring inmem sink")
|
|
|
|
inmemSink, err = inmem.New(&sink.SinkConfig{
|
|
|
|
Logger: apiProxyLogger,
|
|
|
|
}, leaseCache)
|
2021-10-16 00:22:19 +00:00
|
|
|
if err != nil {
|
2022-12-05 15:51:03 +00:00
|
|
|
c.UI.Error(fmt.Sprintf("Error creating inmem sink for cache: %v", err))
|
2021-10-16 00:22:19 +00:00
|
|
|
return 1
|
|
|
|
}
|
2022-12-05 15:51:03 +00:00
|
|
|
sinks = append(sinks, &sink.SinkConfig{
|
|
|
|
Logger: apiProxyLogger,
|
|
|
|
Sink: inmemSink,
|
|
|
|
})
|
2019-02-15 01:10:36 +00:00
|
|
|
}
|
2022-12-05 15:51:03 +00:00
|
|
|
proxyVaultToken = !config.APIProxy.ForceAutoAuthToken
|
|
|
|
}
|
2019-02-15 01:10:36 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
muxHandler := cache.ProxyHandler(ctx, apiProxyLogger, apiProxy, inmemSink, proxyVaultToken)
|
2019-02-15 01:10:36 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
// Parse 'require_request_header' listener config option, and wrap
|
|
|
|
// the request handler if necessary
|
|
|
|
if lnConfig.RequireRequestHeader && ("metrics_only" != lnConfig.Role) {
|
|
|
|
muxHandler = verifyRequestHeader(muxHandler)
|
|
|
|
}
|
2019-10-11 22:56:07 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
// Create a muxer and add paths relevant for the lease cache layer
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
quitEnabled := lnConfig.AgentAPI != nil && lnConfig.AgentAPI.EnableQuit
|
2022-02-25 10:29:05 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
mux.Handle(consts.AgentPathMetrics, c.handleMetrics())
|
|
|
|
if "metrics_only" != lnConfig.Role {
|
|
|
|
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
|
|
|
mux.Handle(consts.AgentPathQuit, c.handleQuit(quitEnabled))
|
|
|
|
mux.Handle("/", muxHandler)
|
|
|
|
}
|
2019-02-15 01:10:36 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
scheme := "https://"
|
|
|
|
if tlsConf == nil {
|
|
|
|
scheme = "http://"
|
|
|
|
}
|
|
|
|
if ln.Addr().Network() == "unix" {
|
|
|
|
scheme = "unix://"
|
|
|
|
}
|
2019-03-14 18:53:14 +00:00
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
infoKey := fmt.Sprintf("api address %d", i+1)
|
|
|
|
info[infoKey] = scheme + ln.Addr().String()
|
|
|
|
infoKeys = append(infoKeys, infoKey)
|
|
|
|
|
|
|
|
server := &http.Server{
|
|
|
|
Addr: ln.Addr().String(),
|
|
|
|
TLSConfig: tlsConf,
|
|
|
|
Handler: mux,
|
|
|
|
ReadHeaderTimeout: 10 * time.Second,
|
|
|
|
ReadTimeout: 30 * time.Second,
|
|
|
|
IdleTimeout: 5 * time.Minute,
|
|
|
|
ErrorLog: apiProxyLogger.StandardLogger(nil),
|
2019-02-15 01:10:36 +00:00
|
|
|
}
|
|
|
|
|
2022-12-05 15:51:03 +00:00
|
|
|
go server.Serve(ln)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that listeners are closed at all the exits
|
|
|
|
listenerCloseFunc := func() {
|
|
|
|
for _, ln := range listeners {
|
|
|
|
ln.Close()
|
2019-02-15 01:10:36 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-05 15:51:03 +00:00
|
|
|
defer c.cleanupGuard.Do(listenerCloseFunc)
|
2019-02-15 01:10:36 +00:00
|
|
|
|
2021-02-24 11:58:10 +00:00
|
|
|
// Inform any tests that the server is ready
|
2021-03-18 18:14:09 +00:00
|
|
|
if c.startedCh != nil {
|
|
|
|
close(c.startedCh)
|
2021-02-24 11:58:10 +00:00
|
|
|
}
|
|
|
|
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
// Listen for signals
|
|
|
|
// TODO: implement support for SIGHUP reloading of configuration
|
|
|
|
// signal.Notify(c.signalCh)
|
|
|
|
|
2020-09-30 01:03:09 +00:00
|
|
|
var g run.Group
|
|
|
|
|
|
|
|
// This run group watches for signal termination
|
|
|
|
g.Add(func() error {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-c.ShutdownCh:
|
|
|
|
c.UI.Output("==> Vault agent shutdown triggered")
|
2022-08-29 12:18:47 +00:00
|
|
|
// Notify systemd that the server is shutting down
|
|
|
|
c.notifySystemd(systemd.SdNotifyStopping)
|
2021-03-03 22:01:33 +00:00
|
|
|
// Let the lease cache know this is a shutdown; no need to evict
|
|
|
|
// everything
|
|
|
|
if leaseCache != nil {
|
|
|
|
leaseCache.SetShuttingDown(true)
|
|
|
|
}
|
2020-09-30 01:03:09 +00:00
|
|
|
return nil
|
|
|
|
case <-ctx.Done():
|
2022-08-29 12:18:47 +00:00
|
|
|
c.notifySystemd(systemd.SdNotifyStopping)
|
2020-09-30 01:03:09 +00:00
|
|
|
return nil
|
2020-11-23 22:24:32 +00:00
|
|
|
case <-winsvc.ShutdownChannel():
|
|
|
|
return nil
|
2020-09-30 01:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}, func(error) {})
|
|
|
|
|
2019-02-20 07:11:05 +00:00
|
|
|
// Start auto-auth and sink servers
|
2019-03-15 18:58:53 +00:00
|
|
|
if method != nil {
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
enableTokenCh := len(config.Templates) > 0
|
2022-04-29 16:31:32 +00:00
|
|
|
|
|
|
|
// Auth Handler is going to set its own retry values, so we want to
|
|
|
|
// work on a copy of the client to not affect other subsystems.
|
2022-06-16 22:06:22 +00:00
|
|
|
ahClient, err := c.client.CloneWithHeaders()
|
2022-04-29 16:31:32 +00:00
|
|
|
if err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error cloning client for auth handler: %v", err))
|
|
|
|
return 1
|
|
|
|
}
|
2022-06-16 22:06:22 +00:00
|
|
|
|
|
|
|
if config.DisableIdleConnsAutoAuth {
|
|
|
|
ahClient.SetMaxIdleConnections(-1)
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:59:49 +00:00
|
|
|
if config.DisableKeepAlivesAutoAuth {
|
|
|
|
ahClient.SetDisableKeepAlives(true)
|
|
|
|
}
|
|
|
|
|
2019-03-15 18:58:53 +00:00
|
|
|
ah := auth.NewAuthHandler(&auth.AuthHandlerConfig{
|
|
|
|
Logger: c.logger.Named("auth.handler"),
|
2022-06-16 22:06:22 +00:00
|
|
|
Client: ahClient,
|
2019-03-15 18:58:53 +00:00
|
|
|
WrapTTL: config.AutoAuth.Method.WrapTTL,
|
2022-04-29 16:31:32 +00:00
|
|
|
MinBackoff: config.AutoAuth.Method.MinBackoff,
|
2021-02-23 20:04:21 +00:00
|
|
|
MaxBackoff: config.AutoAuth.Method.MaxBackoff,
|
2019-03-15 18:58:53 +00:00
|
|
|
EnableReauthOnNewCredentials: config.AutoAuth.EnableReauthOnNewCredentials,
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
EnableTemplateTokenCh: enableTokenCh,
|
2021-03-03 22:01:33 +00:00
|
|
|
Token: previousToken,
|
2022-09-15 18:00:31 +00:00
|
|
|
ExitOnError: config.AutoAuth.Method.ExitOnError,
|
2019-03-15 18:58:53 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
ss := sink.NewSinkServer(&sink.SinkServerConfig{
|
|
|
|
Logger: c.logger.Named("sink.server"),
|
2022-06-16 22:06:22 +00:00
|
|
|
Client: ahClient,
|
2022-11-11 10:59:16 +00:00
|
|
|
ExitAfterAuth: config.ExitAfterAuth,
|
2019-03-15 18:58:53 +00:00
|
|
|
})
|
|
|
|
|
Vault Agent Template follow-ups (#7739)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* update test structure
* some test cleanup
* follow up tests
* remove debugging, fix issue in replacing runner config
* need to handle first render/token
* Simplify the blocking logic to support exit after auth
* fix channel name
* expand TestAgent_Template to include multiple scenarios
* cleanup
* test cleanups after feedback
2019-11-11 23:27:23 +00:00
|
|
|
ts := template.NewServer(&template.ServerConfig{
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
Logger: c.logger.Named("template.server"),
|
2022-11-11 10:59:16 +00:00
|
|
|
LogLevel: logLevel,
|
2019-11-12 19:29:29 +00:00
|
|
|
LogWriter: c.logWriter,
|
2021-02-23 14:36:11 +00:00
|
|
|
AgentConfig: config,
|
2022-01-19 17:43:12 +00:00
|
|
|
Namespace: templateNamespace,
|
2022-11-11 10:59:16 +00:00
|
|
|
ExitAfterAuth: config.ExitAfterAuth,
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
})
|
|
|
|
|
2020-09-30 01:03:09 +00:00
|
|
|
g.Add(func() error {
|
|
|
|
return ah.Run(ctx, method)
|
|
|
|
}, func(error) {
|
2021-03-03 22:01:33 +00:00
|
|
|
// Let the lease cache know this is a shutdown; no need to evict
|
|
|
|
// everything
|
|
|
|
if leaseCache != nil {
|
|
|
|
leaseCache.SetShuttingDown(true)
|
|
|
|
}
|
2020-09-30 01:03:09 +00:00
|
|
|
cancelFunc()
|
|
|
|
})
|
|
|
|
|
|
|
|
g.Add(func() error {
|
|
|
|
err := ss.Run(ctx, ah.OutputCh, sinks)
|
|
|
|
c.logger.Info("sinks finished, exiting")
|
|
|
|
|
|
|
|
// Start goroutine to drain from ah.OutputCh from this point onward
|
|
|
|
// to prevent ah.Run from being blocked.
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case <-ah.OutputCh:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Wait until templates are rendered
|
|
|
|
if len(config.Templates) > 0 {
|
|
|
|
<-ts.DoneCh
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}, func(error) {
|
2021-03-03 22:01:33 +00:00
|
|
|
// Let the lease cache know this is a shutdown; no need to evict
|
|
|
|
// everything
|
|
|
|
if leaseCache != nil {
|
|
|
|
leaseCache.SetShuttingDown(true)
|
|
|
|
}
|
2020-09-30 01:03:09 +00:00
|
|
|
cancelFunc()
|
|
|
|
})
|
|
|
|
|
|
|
|
g.Add(func() error {
|
|
|
|
return ts.Run(ctx, ah.TemplateTokenCh, config.Templates)
|
|
|
|
}, func(error) {
|
2021-03-03 22:01:33 +00:00
|
|
|
// Let the lease cache know this is a shutdown; no need to evict
|
|
|
|
// everything
|
|
|
|
if leaseCache != nil {
|
|
|
|
leaseCache.SetShuttingDown(true)
|
|
|
|
}
|
2020-09-30 01:03:09 +00:00
|
|
|
cancelFunc()
|
|
|
|
ts.Stop()
|
|
|
|
})
|
|
|
|
|
2019-03-15 18:58:53 +00:00
|
|
|
}
|
2019-02-20 07:11:05 +00:00
|
|
|
|
2019-02-15 01:10:36 +00:00
|
|
|
// Server configuration output
|
|
|
|
padding := 24
|
|
|
|
sort.Strings(infoKeys)
|
|
|
|
c.UI.Output("==> Vault agent configuration:\n")
|
|
|
|
for _, k := range infoKeys {
|
|
|
|
c.UI.Output(fmt.Sprintf(
|
|
|
|
"%s%s: %s",
|
|
|
|
strings.Repeat(" ", padding-len(k)),
|
|
|
|
strings.Title(k),
|
|
|
|
info[k]))
|
|
|
|
}
|
|
|
|
c.UI.Output("")
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
// Release the log gate.
|
|
|
|
c.logGate.Flush()
|
|
|
|
|
|
|
|
// Write out the PID to the file now that server has successfully started
|
|
|
|
if err := c.storePidFile(config.PidFile); err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error storing PID: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2022-08-29 12:18:47 +00:00
|
|
|
// Notify systemd that the server is ready (if applicable)
|
|
|
|
c.notifySystemd(systemd.SdNotifyReady)
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
defer func() {
|
|
|
|
if err := c.removePidFile(config.PidFile); err != nil {
|
|
|
|
c.UI.Error(fmt.Sprintf("Error deleting the PID file: %s", err))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-09-30 01:03:09 +00:00
|
|
|
if err := g.Run(); err != nil {
|
|
|
|
c.logger.Error("runtime error encountered", "error", err)
|
|
|
|
c.UI.Error("Error encountered during run, refer to logs for more details.")
|
|
|
|
return 1
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2022-11-29 14:07:04 +00:00
|
|
|
// updateConfig ensures that the config object accurately reflects the desired
|
2022-11-11 10:59:16 +00:00
|
|
|
// settings as configured by the user. It applies the relevant config setting based
|
|
|
|
// on the precedence (env var overrides file config, cli overrides env var).
|
2022-11-29 14:07:04 +00:00
|
|
|
// It mutates the config object supplied.
|
|
|
|
func (c *AgentCommand) updateConfig(f *FlagSets, config *agentConfig.Config) {
|
|
|
|
f.updateLogConfig(config.SharedConfig)
|
|
|
|
|
2022-11-11 10:59:16 +00:00
|
|
|
f.Visit(func(fl *flag.Flag) {
|
|
|
|
if fl.Name == flagNameAgentExitAfterAuth {
|
|
|
|
config.ExitAfterAuth = c.flagExitAfterAuth
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
c.setStringFlag(f, config.Vault.Address, &StringVar{
|
|
|
|
Name: flagNameAddress,
|
|
|
|
Target: &c.flagAddress,
|
|
|
|
Default: "https://127.0.0.1:8200",
|
|
|
|
EnvVar: api.EnvVaultAddress,
|
|
|
|
})
|
|
|
|
config.Vault.Address = c.flagAddress
|
|
|
|
c.setStringFlag(f, config.Vault.CACert, &StringVar{
|
|
|
|
Name: flagNameCACert,
|
|
|
|
Target: &c.flagCACert,
|
|
|
|
Default: "",
|
|
|
|
EnvVar: api.EnvVaultCACert,
|
|
|
|
})
|
|
|
|
config.Vault.CACert = c.flagCACert
|
|
|
|
c.setStringFlag(f, config.Vault.CAPath, &StringVar{
|
|
|
|
Name: flagNameCAPath,
|
|
|
|
Target: &c.flagCAPath,
|
|
|
|
Default: "",
|
|
|
|
EnvVar: api.EnvVaultCAPath,
|
|
|
|
})
|
|
|
|
config.Vault.CAPath = c.flagCAPath
|
|
|
|
c.setStringFlag(f, config.Vault.ClientCert, &StringVar{
|
|
|
|
Name: flagNameClientCert,
|
|
|
|
Target: &c.flagClientCert,
|
|
|
|
Default: "",
|
|
|
|
EnvVar: api.EnvVaultClientCert,
|
|
|
|
})
|
|
|
|
config.Vault.ClientCert = c.flagClientCert
|
|
|
|
c.setStringFlag(f, config.Vault.ClientKey, &StringVar{
|
|
|
|
Name: flagNameClientKey,
|
|
|
|
Target: &c.flagClientKey,
|
|
|
|
Default: "",
|
|
|
|
EnvVar: api.EnvVaultClientKey,
|
|
|
|
})
|
|
|
|
config.Vault.ClientKey = c.flagClientKey
|
|
|
|
c.setBoolFlag(f, config.Vault.TLSSkipVerify, &BoolVar{
|
|
|
|
Name: flagNameTLSSkipVerify,
|
|
|
|
Target: &c.flagTLSSkipVerify,
|
|
|
|
Default: false,
|
|
|
|
EnvVar: api.EnvVaultSkipVerify,
|
|
|
|
})
|
|
|
|
config.Vault.TLSSkipVerify = c.flagTLSSkipVerify
|
|
|
|
c.setStringFlag(f, config.Vault.TLSServerName, &StringVar{
|
|
|
|
Name: flagTLSServerName,
|
|
|
|
Target: &c.flagTLSServerName,
|
|
|
|
Default: "",
|
|
|
|
EnvVar: api.EnvVaultTLSServerName,
|
|
|
|
})
|
|
|
|
config.Vault.TLSServerName = c.flagTLSServerName
|
|
|
|
}
|
|
|
|
|
2019-10-11 22:56:07 +00:00
|
|
|
// verifyRequestHeader wraps an http.Handler inside a Handler that checks for
|
|
|
|
// the request header that is used for SSRF protection.
|
|
|
|
func verifyRequestHeader(handler http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if val, ok := r.Header[consts.RequestHeaderName]; !ok || len(val) != 1 || val[0] != "true" {
|
|
|
|
logical.RespondError(w,
|
|
|
|
http.StatusPreconditionFailed,
|
2022-08-03 18:32:45 +00:00
|
|
|
fmt.Errorf("missing %q header", consts.RequestHeaderName))
|
2019-10-11 22:56:07 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
handler.ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-29 12:18:47 +00:00
|
|
|
func (c *AgentCommand) notifySystemd(status string) {
|
|
|
|
sent, err := systemd.SdNotify(false, status)
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Error("error notifying systemd", "error", err)
|
|
|
|
} else {
|
|
|
|
if sent {
|
|
|
|
c.logger.Debug("sent systemd notification", "notification", status)
|
|
|
|
} else {
|
|
|
|
c.logger.Debug("would have sent systemd notification (systemd not present)", "notification", status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 22:29:28 +00:00
|
|
|
func (c *AgentCommand) setStringFlag(f *FlagSets, configVal string, fVar *StringVar) {
|
|
|
|
var isFlagSet bool
|
|
|
|
f.Visit(func(f *flag.Flag) {
|
|
|
|
if f.Name == fVar.Name {
|
|
|
|
isFlagSet = true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
flagEnvValue, flagEnvSet := os.LookupEnv(fVar.EnvVar)
|
|
|
|
switch {
|
|
|
|
case isFlagSet:
|
|
|
|
// Don't do anything as the flag is already set from the command line
|
|
|
|
case flagEnvSet:
|
|
|
|
// Use value from env var
|
|
|
|
*fVar.Target = flagEnvValue
|
|
|
|
case configVal != "":
|
|
|
|
// Use value from config
|
|
|
|
*fVar.Target = configVal
|
|
|
|
default:
|
|
|
|
// Use the default value
|
|
|
|
*fVar.Target = fVar.Default
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *AgentCommand) setBoolFlag(f *FlagSets, configVal bool, fVar *BoolVar) {
|
|
|
|
var isFlagSet bool
|
|
|
|
f.Visit(func(f *flag.Flag) {
|
|
|
|
if f.Name == fVar.Name {
|
|
|
|
isFlagSet = true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
flagEnvValue, flagEnvSet := os.LookupEnv(fVar.EnvVar)
|
|
|
|
switch {
|
|
|
|
case isFlagSet:
|
|
|
|
// Don't do anything as the flag is already set from the command line
|
|
|
|
case flagEnvSet:
|
|
|
|
// Use value from env var
|
|
|
|
*fVar.Target = flagEnvValue != ""
|
2021-09-30 11:33:14 +00:00
|
|
|
case configVal:
|
2019-02-28 22:29:28 +00:00
|
|
|
// Use value from config
|
|
|
|
*fVar.Target = configVal
|
|
|
|
default:
|
|
|
|
// Use the default value
|
|
|
|
*fVar.Target = fVar.Default
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 02:02:27 +00:00
|
|
|
// storePidFile is used to write out our PID to a file if necessary
|
|
|
|
func (c *AgentCommand) storePidFile(pidPath string) error {
|
|
|
|
// Quit fast if no pidfile
|
|
|
|
if pidPath == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open the PID file
|
2022-04-01 16:57:38 +00:00
|
|
|
pidFile, err := os.OpenFile(pidPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
|
2018-07-25 02:02:27 +00:00
|
|
|
if err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return fmt.Errorf("could not open pid file: %w", err)
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
defer pidFile.Close()
|
|
|
|
|
|
|
|
// Write out the PID
|
|
|
|
pid := os.Getpid()
|
|
|
|
_, err = pidFile.WriteString(fmt.Sprintf("%d", pid))
|
|
|
|
if err != nil {
|
2021-06-02 13:22:31 +00:00
|
|
|
return fmt.Errorf("could not write to pid file: %w", err)
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// removePidFile is used to cleanup the PID file if necessary
|
|
|
|
func (c *AgentCommand) removePidFile(pidPath string) error {
|
|
|
|
if pidPath == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return os.Remove(pidPath)
|
|
|
|
}
|
2021-03-03 22:01:33 +00:00
|
|
|
|
|
|
|
// GetServiceAccountJWT reads the service account jwt from `tokenFile`. Default is
|
|
|
|
// the default service account file path in kubernetes.
|
|
|
|
func getServiceAccountJWT(tokenFile string) (string, error) {
|
|
|
|
if len(tokenFile) == 0 {
|
|
|
|
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
|
|
|
}
|
|
|
|
token, err := ioutil.ReadFile(tokenFile)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(string(token)), nil
|
|
|
|
}
|
2022-02-18 01:10:26 +00:00
|
|
|
|
|
|
|
func (c *AgentCommand) handleMetrics() http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if r.Method != http.MethodGet {
|
|
|
|
logical.RespondError(w, http.StatusMethodNotAllowed, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
|
|
logical.RespondError(w, http.StatusBadRequest, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
format := r.Form.Get("format")
|
|
|
|
if format == "" {
|
|
|
|
format = metricsutil.FormatFromRequest(&logical.Request{
|
|
|
|
Headers: r.Header,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := c.metricsHelper.ResponseForFormat(format)
|
|
|
|
|
|
|
|
status := resp.Data[logical.HTTPStatusCode].(int)
|
|
|
|
w.Header().Set("Content-Type", resp.Data[logical.HTTPContentType].(string))
|
|
|
|
switch v := resp.Data[logical.HTTPRawBody].(type) {
|
|
|
|
case string:
|
|
|
|
w.WriteHeader((status))
|
|
|
|
w.Write([]byte(v))
|
|
|
|
case []byte:
|
|
|
|
w.WriteHeader(status)
|
|
|
|
w.Write(v)
|
|
|
|
default:
|
|
|
|
logical.RespondError(w, http.StatusInternalServerError, fmt.Errorf("wrong response returned"))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-02-25 10:29:05 +00:00
|
|
|
|
|
|
|
func (c *AgentCommand) handleQuit(enabled bool) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if !enabled {
|
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch r.Method {
|
|
|
|
case http.MethodPost:
|
|
|
|
default:
|
|
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.logger.Debug("received quit request")
|
|
|
|
close(c.ShutdownCh)
|
|
|
|
})
|
|
|
|
}
|