agent: route templating server through cache (#10927)

* agent: route templating server through cache

* Remove TemplateRetry, fix unix path

* Remove mtls comment, remove redundant tls enable

* Fix test

* Refactor vault address logic

* Fix cert/key for mtls

* Update command/agent/template/template_test.go

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>

* Update command/agent/template/template_test.go

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>

* Update command/agent/template/template_test.go

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>

* Update command/agent/template/template_test.go

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>

* Update command/agent/template/template_test.go

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>

* Update command/agent/template/template_test.go

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>

* Reject mtls listeners

* changelog

Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>
This commit is contained in:
Jason O'Donnell 2021-02-23 09:36:11 -05:00 committed by GitHub
parent b54bc22f9e
commit 458061d43b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 287 additions and 18 deletions

3
changelog/10927.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
agent: Route templating server through cache when enabled.
```

View File

@ -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,
})

View File

@ -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,
}
}

View File

@ -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,9 +408,11 @@ func TestServerRun(t *testing.T) {
ctx, _ := context.WithTimeout(context.Background(), 20*time.Second)
sc := ServerConfig{
Logger: logging.NewVaultLogger(hclog.Trace),
VaultConf: &config.Vault{
AgentConfig: &config.Config{
Vault: &config.Vault{
Address: ts.URL,
},
},
LogLevel: hclog.Trace,
LogWriter: hclog.DefaultOutput,
ExitAfterAuth: true,