diff --git a/changelog/10927.txt b/changelog/10927.txt new file mode 100644 index 000000000000..80828de57ecd --- /dev/null +++ b/changelog/10927.txt @@ -0,0 +1,3 @@ +```release-note:improvement +agent: Route templating server through cache when enabled. +``` diff --git a/command/agent.go b/command/agent.go index 3ee5bafe04fa..66ad04430ed6 100644 --- a/command/agent.go +++ b/command/agent.go @@ -589,8 +589,7 @@ func (c *AgentCommand) Run(args []string) int { Logger: c.logger.Named("template.server"), LogLevel: level, LogWriter: c.logWriter, - VaultConf: config.Vault, - TemplateRetry: config.TemplateRetry, + AgentConfig: config, Namespace: namespace, ExitAfterAuth: exitAfterAuth, }) diff --git a/command/agent/template/template.go b/command/agent/template/template.go index 728c300a4173..b1b69b30fe91 100644 --- a/command/agent/template/template.go +++ b/command/agent/template/template.go @@ -27,9 +27,9 @@ import ( type ServerConfig struct { Logger hclog.Logger // Client *api.Client - VaultConf *config.Vault + AgentConfig *config.Config + ExitAfterAuth bool - TemplateRetry *config.TemplateRetry Namespace string // LogLevel is needed to set the internal Consul Template Runner's log level @@ -164,12 +164,12 @@ func (ts *Server) Run(ctx context.Context, incoming chan string, templates []*ct }, } - if ts.config.TemplateRetry != nil && ts.config.TemplateRetry.Enabled { + if ts.config.AgentConfig.TemplateRetry != nil && ts.config.AgentConfig.TemplateRetry.Enabled { ctv.Vault.Retry = &ctconfig.RetryConfig{ - Attempts: &ts.config.TemplateRetry.Attempts, - Backoff: &ts.config.TemplateRetry.Backoff, - MaxBackoff: &ts.config.TemplateRetry.MaxBackoff, - Enabled: &ts.config.TemplateRetry.Enabled, + Attempts: &ts.config.AgentConfig.TemplateRetry.Attempts, + Backoff: &ts.config.AgentConfig.TemplateRetry.Backoff, + MaxBackoff: &ts.config.AgentConfig.TemplateRetry.MaxBackoff, + Enabled: &ts.config.AgentConfig.TemplateRetry.Enabled, } } else if ts.testingLimitRetry != 0 { // If we're testing, limit retries to 3 attempts to avoid @@ -239,7 +239,7 @@ func newRunnerConfig(sc *ServerConfig, templates ctconfig.TemplateConfigs) (*ctc // Always set these to ensure nothing is picked up from the environment conf.Vault.RenewToken = pointerutil.BoolPtr(false) conf.Vault.Token = pointerutil.StringPtr("") - conf.Vault.Address = &sc.VaultConf.Address + conf.Vault.Address = &sc.AgentConfig.Vault.Address if sc.Namespace != "" { conf.Vault.Namespace = &sc.Namespace @@ -255,16 +255,35 @@ func newRunnerConfig(sc *ServerConfig, templates ctconfig.TemplateConfigs) (*ctc ServerName: pointerutil.StringPtr(""), } - if strings.HasPrefix(sc.VaultConf.Address, "https") || sc.VaultConf.CACert != "" { - skipVerify := sc.VaultConf.TLSSkipVerify + // Use the cache if available or fallback to the Vault server values. + if sc.AgentConfig.Cache != nil && len(sc.AgentConfig.Listeners) != 0 { + scheme := "unix://" + if sc.AgentConfig.Listeners[0].Type == "tcp" { + scheme = "https://" + if sc.AgentConfig.Listeners[0].TLSDisable { + scheme = "http://" + } + } + address := fmt.Sprintf("%s%s", scheme, sc.AgentConfig.Listeners[0].Address) + conf.Vault.Address = &address + + // Skip verification if its using the cache because they're part of the same agent. + if scheme == "https://" { + if sc.AgentConfig.Listeners[0].TLSRequireAndVerifyClientCert { + return nil, errors.New("template server cannot use local cache when mTLS is enabled") + } + conf.Vault.SSL.Verify = pointerutil.BoolPtr(false) + } + } else if strings.HasPrefix(sc.AgentConfig.Vault.Address, "https") || sc.AgentConfig.Vault.CACert != "" { + skipVerify := sc.AgentConfig.Vault.TLSSkipVerify verify := !skipVerify conf.Vault.SSL = &ctconfig.SSLConfig{ Enabled: pointerutil.BoolPtr(true), Verify: &verify, - Cert: &sc.VaultConf.ClientCert, - Key: &sc.VaultConf.ClientKey, - CaCert: &sc.VaultConf.CACert, - CaPath: &sc.VaultConf.CAPath, + Cert: &sc.AgentConfig.Vault.ClientCert, + Key: &sc.AgentConfig.Vault.ClientKey, + CaCert: &sc.AgentConfig.Vault.CACert, + CaPath: &sc.AgentConfig.Vault.CAPath, } } diff --git a/command/agent/template/template_test.go b/command/agent/template/template_test.go index 912e38d5d31c..347364c79096 100644 --- a/command/agent/template/template_test.go +++ b/command/agent/template/template_test.go @@ -14,6 +14,7 @@ import ( ctconfig "github.com/hashicorp/consul-template/config" "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/command/agent/config" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/sdk/helper/logging" "github.com/hashicorp/vault/sdk/helper/pointerutil" ) @@ -27,6 +28,251 @@ func TestNewServer(t *testing.T) { } } +func newAgentConfig(listeners []*configutil.Listener, enableCache bool) *config.Config { + agentConfig := &config.Config{ + SharedConfig: &configutil.SharedConfig{ + PidFile: "./pidfile", + Listeners: listeners, + }, + AutoAuth: &config.AutoAuth{ + Method: &config.Method{ + Type: "aws", + MountPath: "auth/aws", + Config: map[string]interface{}{ + "role": "foobar", + }, + }, + Sinks: []*config.Sink{ + { + Type: "file", + DHType: "curve25519", + DHPath: "/tmp/file-foo-dhpath", + AAD: "foobar", + Config: map[string]interface{}{ + "path": "/tmp/file-foo", + }, + }, + }, + }, + Vault: &config.Vault{ + Address: "http://127.0.0.1:1111", + CACert: "config_ca_cert", + CAPath: "config_ca_path", + TLSSkipVerifyRaw: interface{}("true"), + TLSSkipVerify: true, + ClientCert: "config_client_cert", + ClientKey: "config_client_key", + }, + } + if enableCache { + agentConfig.Cache = &config.Cache{UseAutoAuthToken: true} + } + + return agentConfig +} + +func TestCacheConfigUnix(t *testing.T) { + listeners := []*configutil.Listener{ + { + Type: "unix", + Address: "foobar", + TLSDisable: true, + SocketMode: "configmode", + SocketUser: "configuser", + SocketGroup: "configgroup", + }, + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + { + Type: "tcp", + Address: "127.0.0.1:8400", + TLSKeyFile: "/path/to/cakey.pem", + TLSCertFile: "/path/to/cacert.pem", + }, + } + + agentConfig := newAgentConfig(listeners, true) + serverConfig := ServerConfig{AgentConfig: agentConfig} + + ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{}) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + expected := "unix://foobar" + if *ctConfig.Vault.Address != expected { + t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address) + } +} + +func TestCacheConfigHTTP(t *testing.T) { + listeners := []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSDisable: true, + }, + { + Type: "unix", + Address: "foobar", + TLSDisable: true, + SocketMode: "configmode", + SocketUser: "configuser", + SocketGroup: "configgroup", + }, + { + Type: "tcp", + Address: "127.0.0.1:8400", + TLSKeyFile: "/path/to/cakey.pem", + TLSCertFile: "/path/to/cacert.pem", + }, + } + + agentConfig := newAgentConfig(listeners, true) + serverConfig := ServerConfig{AgentConfig: agentConfig} + + ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{}) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + expected := "http://127.0.0.1:8300" + if *ctConfig.Vault.Address != expected { + t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address) + } +} + +func TestCacheConfigHTTPS(t *testing.T) { + listeners := []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSKeyFile: "/path/to/cakey.pem", + TLSCertFile: "/path/to/cacert.pem", + }, + { + Type: "unix", + Address: "foobar", + TLSDisable: true, + SocketMode: "configmode", + SocketUser: "configuser", + SocketGroup: "configgroup", + }, + { + Type: "tcp", + Address: "127.0.0.1:8400", + TLSDisable: true, + }, + } + + agentConfig := newAgentConfig(listeners, true) + serverConfig := ServerConfig{AgentConfig: agentConfig} + + ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{}) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + expected := "https://127.0.0.1:8300" + if *ctConfig.Vault.Address != expected { + t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address) + } + + if *ctConfig.Vault.SSL.Verify { + t.Fatalf("expected %t, got %t", true, *ctConfig.Vault.SSL.Verify) + } +} + +func TestCacheConfigNoCache(t *testing.T) { + listeners := []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSKeyFile: "/path/to/cakey.pem", + TLSCertFile: "/path/to/cacert.pem", + }, + { + Type: "unix", + Address: "foobar", + TLSDisable: true, + SocketMode: "configmode", + SocketUser: "configuser", + SocketGroup: "configgroup", + }, + { + Type: "tcp", + Address: "127.0.0.1:8400", + TLSDisable: true, + }, + } + + agentConfig := newAgentConfig(listeners, false) + serverConfig := ServerConfig{AgentConfig: agentConfig} + + ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{}) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + expected := "http://127.0.0.1:1111" + if *ctConfig.Vault.Address != expected { + t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address) + } +} + +func TestCacheConfigNoListener(t *testing.T) { + listeners := []*configutil.Listener{} + + agentConfig := newAgentConfig(listeners, true) + serverConfig := ServerConfig{AgentConfig: agentConfig} + + ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{}) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + expected := "http://127.0.0.1:1111" + if *ctConfig.Vault.Address != expected { + t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address) + } +} + +func TestCacheConfigRejectMTLS(t *testing.T) { + listeners := []*configutil.Listener{ + { + Type: "tcp", + Address: "127.0.0.1:8300", + TLSKeyFile: "/path/to/cakey.pem", + TLSCertFile: "/path/to/cacert.pem", + TLSRequireAndVerifyClientCert: true, + }, + { + Type: "unix", + Address: "foobar", + TLSDisable: true, + SocketMode: "configmode", + SocketUser: "configuser", + SocketGroup: "configgroup", + }, + { + Type: "tcp", + Address: "127.0.0.1:8400", + TLSDisable: true, + }, + } + + agentConfig := newAgentConfig(listeners, true) + serverConfig := ServerConfig{AgentConfig: agentConfig} + + _, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{}) + if err == nil { + t.Fatal("expected error, got none") + } +} + func TestServerRun(t *testing.T) { // create http test server mux := http.NewServeMux() @@ -162,8 +408,10 @@ func TestServerRun(t *testing.T) { ctx, _ := context.WithTimeout(context.Background(), 20*time.Second) sc := ServerConfig{ Logger: logging.NewVaultLogger(hclog.Trace), - VaultConf: &config.Vault{ - Address: ts.URL, + AgentConfig: &config.Config{ + Vault: &config.Vault{ + Address: ts.URL, + }, }, LogLevel: hclog.Trace, LogWriter: hclog.DefaultOutput,