Skip to content

Commit

Permalink
Add annotations to configure Agent Cache (#132)
Browse files Browse the repository at this point in the history
* Add annotations to configure Agent Cache

- TLS is always disabled because there is no way to mount arbitrary
volumes to the agent sidecar container

* Allow configuring listener port and not address
  • Loading branch information
lawliet89 authored Jun 4, 2020
1 parent 4779c11 commit d0c76c7
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 0 deletions.
29 changes: 29 additions & 0 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const (
DefaultAgentRunAsGroup = 1000
DefaultAgentRunAsSameUser = false
DefaultAgentSetSecurityContext = true

DefaultAgentCacheEnable = "false"
DefaultAgentCacheUseAutoAuthToken = "true"
DefaultAgentCacheListenerPort = "8200"
)

// Agent is the top level structure holding all the
Expand Down Expand Up @@ -101,6 +105,9 @@ type Agent struct {
// Vault is the structure holding all the Vault specific configurations.
Vault Vault

// VaultAgentCache is the structure holding the Vault agent cache specific configurations
VaultAgentCache VaultAgentCache

// RunAsUser is the user ID to run the Vault agent container(s) as.
RunAsUser int64

Expand Down Expand Up @@ -185,6 +192,17 @@ type Vault struct {
TLSServerName string
}

type VaultAgentCache struct {
// Enable configures whether the cache is enabled or not
Enable bool

// ListenerPort is the port the cache should listen to
ListenerPort string

// UseAutoAuthToken configures whether the auto auth token is used in cache requests
UseAutoAuthToken string
}

// New creates a new instance of Agent by parsing all the Kubernetes annotations.
func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, error) {
saName, saPath := serviceaccount(pod)
Expand Down Expand Up @@ -277,6 +295,17 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
return agent, err
}

agentCacheEnable, err := agent.agentCacheEnable()
if err != nil {
return agent, err
}

agent.VaultAgentCache = VaultAgentCache{
Enable: agentCacheEnable,
ListenerPort: pod.Annotations[AnnotationAgentCacheListenerPort],
UseAutoAuthToken: pod.Annotations[AnnotationAgentCacheUseAutoAuthToken],
}

return agent, nil
}

Expand Down
32 changes: 32 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ const (
// AnnotationPreserveSecretCase if enabled will preserve the case of secret name
// by default the name is converted to lower case.
AnnotationPreserveSecretCase = "vault.hashicorp.com/preserve-secret-case"

// AnnotationAgentCacheEnable if enabled will configure the sidecar container
// to enable agent caching
AnnotationAgentCacheEnable = "vault.hashicorp.com/agent-cache-enable"

// AnnotationAgentCacheUseAutoAuthToken configures the agent cache to use the
// auto auth token or not. Can be set to "force" to force usage of the auto-auth token
AnnotationAgentCacheUseAutoAuthToken = "vault.hashicorp.com/agent-cache-use-auth-auth-token"

// AnnotationAgentCacheListenerPort configures the port the agent cache should listen on
AnnotationAgentCacheListenerPort = "vault.hashicorp.com/agent-cache-listener-port"
)

type AgentConfig struct {
Expand Down Expand Up @@ -291,6 +302,18 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
pod.ObjectMeta.Annotations[AnnotationAgentSetSecurityContext] = strconv.FormatBool(true)
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationAgentCacheEnable]; !ok {
pod.ObjectMeta.Annotations[AnnotationAgentCacheEnable] = DefaultAgentCacheEnable
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationAgentCacheListenerPort]; !ok {
pod.ObjectMeta.Annotations[AnnotationAgentCacheListenerPort] = DefaultAgentCacheListenerPort
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationAgentCacheUseAutoAuthToken]; !ok {
pod.ObjectMeta.Annotations[AnnotationAgentCacheUseAutoAuthToken] = DefaultAgentCacheUseAutoAuthToken
}

return nil
}

Expand Down Expand Up @@ -464,3 +487,12 @@ func (a *Agent) setSecurityContext() (bool, error) {

return strconv.ParseBool(raw)
}

func (a *Agent) agentCacheEnable() (bool, error) {
raw, ok := a.Annotations[AnnotationAgentCacheEnable]
if !ok {
return false, nil
}

return strconv.ParseBool(raw)
}
12 changes: 12 additions & 0 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,18 @@ func TestCouldErrorAnnotations(t *testing.T) {
{AnnotationAgentSetSecurityContext, "false", true},
{AnnotationAgentSetSecurityContext, "secure", false},
{AnnotationAgentSetSecurityContext, "", false},

{AnnotationAgentCacheEnable, "true", true},
{AnnotationAgentCacheEnable, "false", true},
{AnnotationAgentCacheEnable, "TRUE", true},
{AnnotationAgentCacheEnable, "FALSE", true},
{AnnotationAgentCacheEnable, "0", true},
{AnnotationAgentCacheEnable, "1", true},
{AnnotationAgentCacheEnable, "t", true},
{AnnotationAgentCacheEnable, "f", true},
{AnnotationAgentCacheEnable, "tRuE", false},
{AnnotationAgentCacheEnable, "fAlSe", false},
{AnnotationAgentCacheEnable, "", false},
}

for i, tt := range tests {
Expand Down
27 changes: 27 additions & 0 deletions agent-inject/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type Config struct {
PidFile string `json:"pid_file"`
Vault *VaultConfig `json:"vault"`
Templates []*Template `json:"template"`
Listener []*Listener `json:"listener,omitempty"`
Cache *Cache `json:"cache,omitempty"`
}

// Vault contains configuration for connecting to Vault servers
Expand Down Expand Up @@ -73,6 +75,18 @@ type Template struct {
Command string `json:"command,omitempty"`
}

// Listener defines the configuration for Vault Agent Cache Listener
type Listener struct {
Type string `json:"type"`
Address string `json:"address"`
TLSDisable bool `json:"tls_disable"`
}

// Cache defines the configuration for the Vault Agent Cache
type Cache struct {
UseAuthAuthToken string `json:"use_auto_auth_token"`
}

func (a *Agent) newTemplateConfigs() []*Template {
var templates []*Template
for _, secret := range a.Secrets {
Expand Down Expand Up @@ -127,6 +141,19 @@ func (a *Agent) newConfig(init bool) ([]byte, error) {
Templates: a.newTemplateConfigs(),
}

if a.VaultAgentCache.Enable && !init {
config.Listener = []*Listener{
{
Type: "tcp",
Address: fmt.Sprintf("127.0.0.1:%s", a.VaultAgentCache.ListenerPort),
TLSDisable: true,
},
}
config.Cache = &Cache{
UseAuthAuthToken: a.VaultAgentCache.UseAutoAuthToken,
}
}

return config.render()
}

Expand Down
109 changes: 109 additions & 0 deletions agent-inject/agent/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,27 @@ func TestNewConfig(t *testing.T) {
fmt.Sprintf("%s-%s", AnnotationVaultSecretVolumePath, "different-path"): "/etc/container_environment",

"vault.hashicorp.com/agent-inject-command-bar": "pkill -HUP app",

AnnotationAgentCacheEnable: "true",
}

pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error initialising pod, shouldn't have: %s", err)
}

agent, err := New(pod, patches)
if err != nil {
t.Errorf("got error creating agent, shouldn't have: %s", err)
}

cfg, err := agent.newConfig(true)
if err != nil {
t.Errorf("got error creating Vault config, shouldn't have: %s", err)
Expand Down Expand Up @@ -89,6 +104,10 @@ func TestNewConfig(t *testing.T) {
t.Errorf("auto_auth mount path: expected path to be %s, got %s", annotations[AnnotationVaultAuthPath], config.AutoAuth.Method.MountPath)
}

if len(config.Listener) != 0 || config.Cache != nil {
t.Error("agent Cache should be disabled for init containers")
}

if len(config.Templates) != 3 {
t.Errorf("expected 3 template, got %d", len(config.Templates))
}
Expand Down Expand Up @@ -122,3 +141,93 @@ func TestNewConfig(t *testing.T) {
}
}
}

func TestConfigVaultAgentCacheNotEnabledByDefault(t *testing.T) {
annotations := map[string]string{}

pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error initialising pod, shouldn't have: %s", err)
}

agent, err := New(pod, patches)
if err != nil {
t.Errorf("got error creating agent, shouldn't have: %s", err)
}

cfg, err := agent.newConfig(false)
if err != nil {
t.Errorf("got error creating Vault config, shouldn't have: %s", err)
}

config := &Config{}
if err := json.Unmarshal(cfg, config); err != nil {
t.Errorf("got error unmarshalling Vault config, shouldn't have: %s", err)
}

if len(config.Listener) != 0 || config.Cache != nil {
t.Error("agent Cache should be not be enabled by default")
}
}

func TestConfigVaultAgentCache(t *testing.T) {
annotations := map[string]string{
AnnotationAgentCacheEnable: "true",
AnnotationAgentCacheUseAutoAuthToken: "force",
AnnotationAgentCacheListenerPort: "8100",
}

pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext,
}
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error initialising pod, shouldn't have: %s", err)
}

agent, err := New(pod, patches)
if err != nil {
t.Errorf("got error creating agent, shouldn't have: %s", err)
}

cfg, err := agent.newConfig(false)
if err != nil {
t.Errorf("got error creating Vault config, shouldn't have: %s", err)
}

config := &Config{}
if err := json.Unmarshal(cfg, config); err != nil {
t.Errorf("got error unmarshalling Vault config, shouldn't have: %s", err)
}

if len(config.Listener) == 0 || config.Cache == nil {
t.Error("agent Cache should be enabled")
}

if config.Cache.UseAuthAuthToken != "force" {
t.Errorf("agent Cache use_auto_auth_token should be 'force', got %s instead", config.Cache.UseAuthAuthToken)
}

if config.Listener[0].Type != "tcp" {
t.Errorf("agent Cache listener type should be tcp, got %s instead", config.Listener[0].Type)
}

if config.Listener[0].Address != "127.0.0.1:8100" {
t.Errorf("agent Cache listener address should be 127.0.0.1:8100, got %s", config.Listener[0].Address)
}

if !config.Listener[0].TLSDisable {
t.Error("agent Cache listener TLS should be disabled")
}
}

0 comments on commit d0c76c7

Please sign in to comment.