agent: Use an in-process listener with cache (#12762)
Uses a bufconn listener between consul-template and vault-agent when caching is enabled and either templates or a listener is defined. This means no listeners need to be defined in vault-agent for just templating. Always routes consul-template through the vault-agent cache (instead of only when persistent cache is enabled). Uses a local transportDialer interface in config.Cache{}. Co-authored-by: Tom Proctor <tomhjp@users.noreply.github.com> Co-authored-by: Ben Ash <32777270+benashz@users.noreply.github.com>
This commit is contained in:
parent
3428de017a
commit
ae79afdd26
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
agent/cache: Use an in-process listener between consul-template and vault-agent when caching is enabled and either templates or a listener is defined
|
||||||
|
```
|
|
@ -2,6 +2,7 @@ package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -40,6 +41,8 @@ import (
|
||||||
"github.com/hashicorp/vault/command/agent/sink/inmem"
|
"github.com/hashicorp/vault/command/agent/sink/inmem"
|
||||||
"github.com/hashicorp/vault/command/agent/template"
|
"github.com/hashicorp/vault/command/agent/template"
|
||||||
"github.com/hashicorp/vault/command/agent/winsvc"
|
"github.com/hashicorp/vault/command/agent/winsvc"
|
||||||
|
"github.com/hashicorp/vault/internalshared/configutil"
|
||||||
|
"github.com/hashicorp/vault/internalshared/listenerutil"
|
||||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||||
"github.com/hashicorp/vault/sdk/helper/logging"
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
@ -48,6 +51,7 @@ import (
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/oklog/run"
|
"github.com/oklog/run"
|
||||||
"github.com/posener/complete"
|
"github.com/posener/complete"
|
||||||
|
"google.golang.org/grpc/test/bufconn"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -470,7 +474,7 @@ func (c *AgentCommand) Run(args []string) int {
|
||||||
var leaseCache *cache.LeaseCache
|
var leaseCache *cache.LeaseCache
|
||||||
var previousToken string
|
var previousToken string
|
||||||
// Parse agent listener configurations
|
// Parse agent listener configurations
|
||||||
if config.Cache != nil && len(config.Listeners) != 0 {
|
if config.Cache != nil {
|
||||||
cacheLogger := c.logger.Named("cache")
|
cacheLogger := c.logger.Named("cache")
|
||||||
|
|
||||||
// Create the API proxier
|
// Create the API proxier
|
||||||
|
@ -666,11 +670,25 @@ func (c *AgentCommand) Run(args []string) int {
|
||||||
cacheHandler := cache.Handler(ctx, cacheLogger, leaseCache, inmemSink, proxyVaultToken)
|
cacheHandler := cache.Handler(ctx, cacheLogger, leaseCache, inmemSink, proxyVaultToken)
|
||||||
|
|
||||||
var listeners []net.Listener
|
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 {
|
for i, lnConfig := range config.Listeners {
|
||||||
ln, tlsConf, err := cache.StartListener(lnConfig)
|
var ln net.Listener
|
||||||
if err != nil {
|
var tlsConf *tls.Config
|
||||||
c.UI.Error(fmt.Sprintf("Error starting listener: %v", err))
|
|
||||||
return 1
|
if lnConfig.Type == listenerutil.BufConnType {
|
||||||
|
inProcListener := bufconn.Listen(1024 * 1024)
|
||||||
|
config.Cache.InProcDialer = listenerutil.NewBufConnWrapper(inProcListener)
|
||||||
|
ln = inProcListener
|
||||||
|
} else {
|
||||||
|
ln, tlsConf, err = cache.StartListener(lnConfig)
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(fmt.Sprintf("Error starting listener: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners = append(listeners, ln)
|
listeners = append(listeners, ln)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -64,14 +66,25 @@ type Vault struct {
|
||||||
Retry *Retry `hcl:"retry"`
|
Retry *Retry `hcl:"retry"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// transportDialer is an interface that allows passing a custom dialer function
|
||||||
|
// to an HTTP client's transport config
|
||||||
|
type transportDialer interface {
|
||||||
|
// Dial is intended to match https://pkg.go.dev/net#Dialer.Dial
|
||||||
|
Dial(network, address string) (net.Conn, error)
|
||||||
|
|
||||||
|
// DialContext is intended to match https://pkg.go.dev/net#Dialer.DialContext
|
||||||
|
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
||||||
|
}
|
||||||
|
|
||||||
// Cache contains any configuration needed for Cache mode
|
// Cache contains any configuration needed for Cache mode
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
UseAutoAuthTokenRaw interface{} `hcl:"use_auto_auth_token"`
|
UseAutoAuthTokenRaw interface{} `hcl:"use_auto_auth_token"`
|
||||||
UseAutoAuthToken bool `hcl:"-"`
|
UseAutoAuthToken bool `hcl:"-"`
|
||||||
ForceAutoAuthToken bool `hcl:"-"`
|
ForceAutoAuthToken bool `hcl:"-"`
|
||||||
EnforceConsistency string `hcl:"enforce_consistency"`
|
EnforceConsistency string `hcl:"enforce_consistency"`
|
||||||
WhenInconsistent string `hcl:"when_inconsistent"`
|
WhenInconsistent string `hcl:"when_inconsistent"`
|
||||||
Persist *Persist `hcl:"persist"`
|
Persist *Persist `hcl:"persist"`
|
||||||
|
InProcDialer transportDialer `hcl:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist contains configuration needed for persistent caching
|
// Persist contains configuration needed for persistent caching
|
||||||
|
@ -203,8 +216,8 @@ func LoadConfig(path string) (*Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.Cache != nil {
|
if result.Cache != nil {
|
||||||
if len(result.Listeners) < 1 {
|
if len(result.Listeners) < 1 && len(result.Templates) < 1 {
|
||||||
return nil, fmt.Errorf("at least one listener required when cache enabled")
|
return nil, fmt.Errorf("enabling the cache requires at least 1 template or 1 listener to be defined")
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.Cache.UseAutoAuthToken {
|
if result.Cache.UseAutoAuthToken {
|
||||||
|
|
|
@ -105,6 +105,74 @@ func TestLoadConfigFile_AgentCache(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigFile_AgentCache_NoListeners(t *testing.T) {
|
||||||
|
config, err := LoadConfig("./test-fixtures/config-cache-no-listeners.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &Config{
|
||||||
|
SharedConfig: &configutil.SharedConfig{
|
||||||
|
PidFile: "./pidfile",
|
||||||
|
},
|
||||||
|
AutoAuth: &AutoAuth{
|
||||||
|
Method: &Method{
|
||||||
|
Type: "aws",
|
||||||
|
MountPath: "auth/aws",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"role": "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Sinks: []*Sink{
|
||||||
|
{
|
||||||
|
Type: "file",
|
||||||
|
DHType: "curve25519",
|
||||||
|
DHPath: "/tmp/file-foo-dhpath",
|
||||||
|
AAD: "foobar",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"path": "/tmp/file-foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Cache: &Cache{
|
||||||
|
UseAutoAuthToken: true,
|
||||||
|
UseAutoAuthTokenRaw: true,
|
||||||
|
ForceAutoAuthToken: false,
|
||||||
|
Persist: &Persist{
|
||||||
|
Type: "kubernetes",
|
||||||
|
Path: "/vault/agent-cache/",
|
||||||
|
KeepAfterImport: true,
|
||||||
|
ExitOnErr: true,
|
||||||
|
ServiceAccountTokenFile: "/tmp/serviceaccount/token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vault: &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",
|
||||||
|
Retry: &Retry{
|
||||||
|
NumRetries: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Templates: []*ctconfig.TemplateConfig{
|
||||||
|
{
|
||||||
|
Source: pointerutil.StringPtr("/path/on/disk/to/template.ctmpl"),
|
||||||
|
Destination: pointerutil.StringPtr("/path/on/disk/where/template/will/render.txt"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Prune()
|
||||||
|
if diff := deep.Equal(config, expected); diff != nil {
|
||||||
|
t.Fatal(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadConfigFile(t *testing.T) {
|
func TestLoadConfigFile(t *testing.T) {
|
||||||
if err := os.Setenv("TEST_AAD_ENV", "aad"); err != nil {
|
if err := os.Setenv("TEST_AAD_ENV", "aad"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -270,7 +338,7 @@ func TestLoadConfigFile_Bad_AgentCache_ForceAutoAuthNoMethod(t *testing.T) {
|
||||||
func TestLoadConfigFile_Bad_AgentCache_NoListeners(t *testing.T) {
|
func TestLoadConfigFile_Bad_AgentCache_NoListeners(t *testing.T) {
|
||||||
_, err := LoadConfig("./test-fixtures/bad-config-cache-no-listeners.hcl")
|
_, err := LoadConfig("./test-fixtures/bad-config-cache-no-listeners.hcl")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("LoadConfig should return an error when cache section present and no listeners present")
|
t.Fatal("LoadConfig should return an error when cache section present and no listeners present and no templates defined")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
pid_file = "./pidfile"
|
||||||
|
|
||||||
|
auto_auth {
|
||||||
|
method {
|
||||||
|
type = "aws"
|
||||||
|
config = {
|
||||||
|
role = "foobar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sink {
|
||||||
|
type = "file"
|
||||||
|
config = {
|
||||||
|
path = "/tmp/file-foo"
|
||||||
|
}
|
||||||
|
aad = "foobar"
|
||||||
|
dh_type = "curve25519"
|
||||||
|
dh_path = "/tmp/file-foo-dhpath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache {
|
||||||
|
use_auto_auth_token = true
|
||||||
|
persist = {
|
||||||
|
type = "kubernetes"
|
||||||
|
path = "/vault/agent-cache/"
|
||||||
|
keep_after_import = true
|
||||||
|
exit_on_err = true
|
||||||
|
service_account_token_file = "/tmp/serviceaccount/token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vault {
|
||||||
|
address = "http://127.0.0.1:1111"
|
||||||
|
ca_cert = "config_ca_cert"
|
||||||
|
ca_path = "config_ca_path"
|
||||||
|
tls_skip_verify = "true"
|
||||||
|
client_cert = "config_client_cert"
|
||||||
|
client_key = "config_client_key"
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
source = "/path/on/disk/to/template.ctmpl"
|
||||||
|
destination = "/path/on/disk/where/template/will/render.txt"
|
||||||
|
}
|
|
@ -264,10 +264,7 @@ func newRunnerConfig(sc *ServerConfig, templates ctconfig.TemplateConfigs) (*ctc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the cache if available or fallback to the Vault server values.
|
// Use the cache if available or fallback to the Vault server values.
|
||||||
// For now we're only routing templating through the cache when persistence
|
if sc.AgentConfig.Cache != nil {
|
||||||
// is enabled. The templating engine and the cache have some inconsistencies
|
|
||||||
// that need to be fixed for 1.7x/1.8
|
|
||||||
if sc.AgentConfig.Cache != nil && sc.AgentConfig.Cache.Persist != nil && len(sc.AgentConfig.Listeners) != 0 {
|
|
||||||
attempts = 0
|
attempts = 0
|
||||||
|
|
||||||
// If we don't want exit on template retry failure (i.e. unlimited
|
// If we don't want exit on template retry failure (i.e. unlimited
|
||||||
|
@ -283,23 +280,18 @@ func newRunnerConfig(sc *ServerConfig, templates ctconfig.TemplateConfigs) (*ctc
|
||||||
attempts = ctconfig.DefaultRetryAttempts
|
attempts = ctconfig.DefaultRetryAttempts
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := "unix://"
|
if sc.AgentConfig.Cache.InProcDialer == nil {
|
||||||
if sc.AgentConfig.Listeners[0].Type == "tcp" {
|
return nil, fmt.Errorf("missing in-process dialer configuration")
|
||||||
scheme = "https://"
|
|
||||||
if sc.AgentConfig.Listeners[0].TLSDisable {
|
|
||||||
scheme = "http://"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
address := fmt.Sprintf("%s%s", scheme, sc.AgentConfig.Listeners[0].Address)
|
if conf.Vault.Transport == nil {
|
||||||
conf.Vault.Address = &address
|
conf.Vault.Transport = &ctconfig.TransportConfig{}
|
||||||
|
}
|
||||||
|
conf.Vault.Transport.CustomDialer = sc.AgentConfig.Cache.InProcDialer
|
||||||
|
// The in-process dialer ignores the address passed in, but we're still
|
||||||
|
// setting it here to override the setting at the top of this function,
|
||||||
|
// and to prevent the vault/http client from defaulting to https.
|
||||||
|
conf.Vault.Address = pointerutil.StringPtr("http://127.0.0.1:8200")
|
||||||
|
|
||||||
// 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 != "" {
|
} else if strings.HasPrefix(sc.AgentConfig.Vault.Address, "https") || sc.AgentConfig.Vault.CACert != "" {
|
||||||
skipVerify := sc.AgentConfig.Vault.TLSSkipVerify
|
skipVerify := sc.AgentConfig.Vault.TLSSkipVerify
|
||||||
verify := !skipVerify
|
verify := !skipVerify
|
||||||
|
|
|
@ -15,8 +15,12 @@ import (
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/vault/command/agent/config"
|
"github.com/hashicorp/vault/command/agent/config"
|
||||||
"github.com/hashicorp/vault/internalshared/configutil"
|
"github.com/hashicorp/vault/internalshared/configutil"
|
||||||
|
"github.com/hashicorp/vault/internalshared/listenerutil"
|
||||||
"github.com/hashicorp/vault/sdk/helper/logging"
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
||||||
"github.com/hashicorp/vault/sdk/helper/pointerutil"
|
"github.com/hashicorp/vault/sdk/helper/pointerutil"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/grpc/test/bufconn"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestNewServer is a simple test to make sure NewServer returns a Server and
|
// TestNewServer is a simple test to make sure NewServer returns a Server and
|
||||||
|
@ -77,44 +81,7 @@ func newAgentConfig(listeners []*configutil.Listener, enableCache, enablePersise
|
||||||
return agentConfig
|
return agentConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheConfigUnix(t *testing.T) {
|
func TestCacheConfig(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, 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{
|
listeners := []*configutil.Listener{
|
||||||
{
|
{
|
||||||
Type: "tcp",
|
Type: "tcp",
|
||||||
|
@ -137,132 +104,69 @@ func TestCacheConfigHTTP(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
agentConfig := newAgentConfig(listeners, true, true)
|
cases := map[string]struct {
|
||||||
serverConfig := ServerConfig{AgentConfig: agentConfig}
|
cacheEnabled bool
|
||||||
|
persistentCacheEnabled bool
|
||||||
ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{})
|
setDialer bool
|
||||||
if err != nil {
|
expectedErr string
|
||||||
t.Fatalf("unexpected error: %s", err)
|
expectCustomDialer bool
|
||||||
}
|
}{
|
||||||
|
"persistent_cache": {
|
||||||
expected := "http://127.0.0.1:8300"
|
cacheEnabled: true,
|
||||||
if *ctConfig.Vault.Address != expected {
|
persistentCacheEnabled: true,
|
||||||
t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address)
|
setDialer: true,
|
||||||
}
|
expectedErr: "",
|
||||||
}
|
expectCustomDialer: true,
|
||||||
|
|
||||||
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",
|
|
||||||
},
|
},
|
||||||
{
|
"memory_cache": {
|
||||||
Type: "unix",
|
cacheEnabled: true,
|
||||||
Address: "foobar",
|
persistentCacheEnabled: false,
|
||||||
TLSDisable: true,
|
setDialer: true,
|
||||||
SocketMode: "configmode",
|
expectedErr: "",
|
||||||
SocketUser: "configuser",
|
expectCustomDialer: true,
|
||||||
SocketGroup: "configgroup",
|
|
||||||
},
|
},
|
||||||
{
|
"no_cache": {
|
||||||
Type: "tcp",
|
cacheEnabled: false,
|
||||||
Address: "127.0.0.1:8400",
|
persistentCacheEnabled: false,
|
||||||
TLSDisable: true,
|
setDialer: false,
|
||||||
|
expectedErr: "",
|
||||||
|
expectCustomDialer: false,
|
||||||
|
},
|
||||||
|
"cache_no_dialer": {
|
||||||
|
cacheEnabled: true,
|
||||||
|
persistentCacheEnabled: false,
|
||||||
|
setDialer: false,
|
||||||
|
expectedErr: "missing in-process dialer configuration",
|
||||||
|
expectCustomDialer: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
agentConfig := newAgentConfig(listeners, true, true)
|
for name, tc := range cases {
|
||||||
serverConfig := ServerConfig{AgentConfig: agentConfig}
|
t.Run(name, func(t *testing.T) {
|
||||||
|
agentConfig := newAgentConfig(listeners, tc.cacheEnabled, tc.persistentCacheEnabled)
|
||||||
|
if tc.setDialer && tc.cacheEnabled {
|
||||||
|
bListener := bufconn.Listen(1024 * 1024)
|
||||||
|
defer bListener.Close()
|
||||||
|
agentConfig.Cache.InProcDialer = listenerutil.NewBufConnWrapper(bListener)
|
||||||
|
}
|
||||||
|
serverConfig := ServerConfig{AgentConfig: agentConfig}
|
||||||
|
|
||||||
ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{})
|
ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{})
|
||||||
if err != nil {
|
if len(tc.expectedErr) > 0 {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
require.Error(t, err, tc.expectedErr)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
expected := "https://127.0.0.1:8300"
|
require.NoError(t, err)
|
||||||
if *ctConfig.Vault.Address != expected {
|
require.NotNil(t, ctConfig)
|
||||||
t.Fatalf("expected %s, got %s", expected, *ctConfig.Vault.Address)
|
assert.Equal(t, tc.expectCustomDialer, ctConfig.Vault.Transport.CustomDialer != nil)
|
||||||
}
|
|
||||||
|
|
||||||
if *ctConfig.Vault.SSL.Verify {
|
if tc.expectCustomDialer {
|
||||||
t.Fatalf("expected %t, got %t", true, *ctConfig.Vault.SSL.Verify)
|
assert.Equal(t, "http://127.0.0.1:8200", *ctConfig.Vault.Address)
|
||||||
}
|
} else {
|
||||||
}
|
assert.Equal(t, "http://127.0.0.1:1111", *ctConfig.Vault.Address)
|
||||||
|
}
|
||||||
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, 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 TestCacheConfigNoPersistentCache(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, 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +174,9 @@ func TestCacheConfigNoListener(t *testing.T) {
|
||||||
listeners := []*configutil.Listener{}
|
listeners := []*configutil.Listener{}
|
||||||
|
|
||||||
agentConfig := newAgentConfig(listeners, true, true)
|
agentConfig := newAgentConfig(listeners, true, true)
|
||||||
|
bListener := bufconn.Listen(1024 * 1024)
|
||||||
|
defer bListener.Close()
|
||||||
|
agentConfig.Cache.InProcDialer = listenerutil.NewBufConnWrapper(bListener)
|
||||||
serverConfig := ServerConfig{AgentConfig: agentConfig}
|
serverConfig := ServerConfig{AgentConfig: agentConfig}
|
||||||
|
|
||||||
ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{})
|
ctConfig, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{})
|
||||||
|
@ -277,43 +184,8 @@ func TestCacheConfigNoListener(t *testing.T) {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "http://127.0.0.1:1111"
|
assert.Equal(t, "http://127.0.0.1:8200", *ctConfig.Vault.Address)
|
||||||
if *ctConfig.Vault.Address != expected {
|
assert.NotNil(t, ctConfig.Vault.Transport.CustomDialer)
|
||||||
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, true)
|
|
||||||
serverConfig := ServerConfig{AgentConfig: agentConfig}
|
|
||||||
|
|
||||||
_, err := newRunnerConfig(&serverConfig, ctconfig.TemplateConfigs{})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected error, got none")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerRun(t *testing.T) {
|
func TestServerRun(t *testing.T) {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -60,7 +60,7 @@ require (
|
||||||
github.com/google/go-metrics-stackdriver v0.2.0
|
github.com/google/go-metrics-stackdriver v0.2.0
|
||||||
github.com/gorilla/mux v1.7.3 // indirect
|
github.com/gorilla/mux v1.7.3 // indirect
|
||||||
github.com/hashicorp/cap v0.1.0
|
github.com/hashicorp/cap v0.1.0
|
||||||
github.com/hashicorp/consul-template v0.27.1
|
github.com/hashicorp/consul-template v0.27.2-0.20211014231529-4ff55381f1c4
|
||||||
github.com/hashicorp/consul/api v1.11.0
|
github.com/hashicorp/consul/api v1.11.0
|
||||||
github.com/hashicorp/errwrap v1.1.0
|
github.com/hashicorp/errwrap v1.1.0
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2
|
github.com/hashicorp/go-cleanhttp v0.5.2
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -569,8 +569,8 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/cap v0.1.0 h1:uBDfu9NDvmotza/mJW6vtQId+VYid9ztlTnDCW6YUWU=
|
github.com/hashicorp/cap v0.1.0 h1:uBDfu9NDvmotza/mJW6vtQId+VYid9ztlTnDCW6YUWU=
|
||||||
github.com/hashicorp/cap v0.1.0/go.mod h1:VfBvK2ULRyqsuqAnjgZl7HJ7/CGMC7ro4H5eXiZuun8=
|
github.com/hashicorp/cap v0.1.0/go.mod h1:VfBvK2ULRyqsuqAnjgZl7HJ7/CGMC7ro4H5eXiZuun8=
|
||||||
github.com/hashicorp/consul-template v0.27.1 h1:VGQDW2DJeZnmtWO2KvEnMBGxmccGTASEW2DsHHz1QRg=
|
github.com/hashicorp/consul-template v0.27.2-0.20211014231529-4ff55381f1c4 h1:Heoq6IaSKwqOzAJMDg33LRu0GmNxVswQkIcREBFQD2E=
|
||||||
github.com/hashicorp/consul-template v0.27.1/go.mod h1:cAi5bOqno7Ao5sFHu7O80wMOPnqcF5ADrTApWU4Lqx4=
|
github.com/hashicorp/consul-template v0.27.2-0.20211014231529-4ff55381f1c4/go.mod h1:cAi5bOqno7Ao5sFHu7O80wMOPnqcF5ADrTApWU4Lqx4=
|
||||||
github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
|
github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
|
||||||
github.com/hashicorp/consul/api v1.11.0 h1:Hw/G8TtRvOElqxVIhBzXciiSTbapq8hZ2XKZsXk5ZCE=
|
github.com/hashicorp/consul/api v1.11.0 h1:Hw/G8TtRvOElqxVIhBzXciiSTbapq8hZ2XKZsXk5ZCE=
|
||||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package listenerutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/test/bufconn"
|
||||||
|
)
|
||||||
|
|
||||||
|
const BufConnType = "bufconn"
|
||||||
|
|
||||||
|
// BufConnWrapper implements consul-template's TransportDialer using a
|
||||||
|
// bufconn listener, to provide a way to Dial the in-memory listener
|
||||||
|
type BufConnWrapper struct {
|
||||||
|
listener *bufconn.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBufConnWrapper returns a new BufConnWrapper using an
|
||||||
|
// existing bufconn.Listener
|
||||||
|
func NewBufConnWrapper(bcl *bufconn.Listener) *BufConnWrapper {
|
||||||
|
return &BufConnWrapper{
|
||||||
|
listener: bcl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial connects to the listening end of the bufconn (satisfies
|
||||||
|
// consul-template's TransportDialer interface). This is essentially the client
|
||||||
|
// side of the bufconn connection.
|
||||||
|
func (bcl *BufConnWrapper) Dial(_, _ string) (net.Conn, error) {
|
||||||
|
return bcl.listener.Dial()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialContext connects to the listening end of the bufconn (satisfies
|
||||||
|
// consul-template's TransportDialer interface). This is essentially the client
|
||||||
|
// side of the bufconn connection.
|
||||||
|
func (bcl *BufConnWrapper) DialContext(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
return bcl.listener.DialContext(ctx)
|
||||||
|
}
|
Loading…
Reference in New Issue