Skip to content

Commit

Permalink
Add flag and annotation to override default template (hashicorp#242)
Browse files Browse the repository at this point in the history
* Add flag/annotation override for default template

* Update deployment

* Fix test

* Clean up test structs

* Update per review
  • Loading branch information
jasonodonnell authored Apr 8, 2021
1 parent c63c262 commit a9f26ad
Show file tree
Hide file tree
Showing 12 changed files with 240 additions and 127 deletions.
13 changes: 13 additions & 0 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type Agent struct {
// configure the Vault Agent container.
Annotations map[string]string

// DefaultTemplate is the default template to be used when
// no custom template is specified via annotations.
DefaultTemplate string

// ImageName is the name of the Vault image to use for the
// sidecar container.
ImageName string
Expand Down Expand Up @@ -251,6 +255,7 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
Annotations: pod.Annotations,
ConfigMapName: pod.Annotations[AnnotationAgentConfigMap],
ImageName: pod.Annotations[AnnotationAgentImage],
DefaultTemplate: pod.Annotations[AnnotationAgentInjectDefaultTemplate],
LimitsCPU: pod.Annotations[AnnotationAgentLimitsCPU],
LimitsMem: pod.Annotations[AnnotationAgentLimitsMem],
Namespace: pod.Annotations[AnnotationAgentRequestNamespace],
Expand Down Expand Up @@ -351,6 +356,14 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
return agent, err
}

agent.DefaultTemplate = strings.ToLower(agent.DefaultTemplate)
switch agent.DefaultTemplate {
case "map":
case "json":
default:
return agent, fmt.Errorf("invalid default template type: %s", agent.DefaultTemplate)
}

agent.VaultAgentCache = VaultAgentCache{
Enable: agentCacheEnable,
ListenerPort: pod.Annotations[AnnotationAgentCacheListenerPort],
Expand Down
9 changes: 9 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const (
// If not provided, a default generic template is used.
AnnotationAgentInjectTemplate = "vault.hashicorp.com/agent-inject-template"

// AnnotationAgentInjectDefaultTemplate sets the default template type. Possible values
// are "json" and "map".
AnnotationAgentInjectDefaultTemplate = "vault.hashicorp.com/agent-inject-default-template"

// AnnotationAgentInjectTemplateFile is the optional key annotation that configures Vault
// Agent what template on disk to use for rendering the secrets. The name
// of the template is any unique string after "vault.hashicorp.com/agent-inject-template-file-",
Expand Down Expand Up @@ -236,6 +240,7 @@ type AgentConfig struct {
SameID bool
SetSecurityContext bool
ProxyAddress string
DefaultTemplate string
ResourceRequestCPU string
ResourceRequestMem string
ResourceLimitCPU string
Expand Down Expand Up @@ -384,6 +389,10 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
pod.ObjectMeta.Annotations[AnnotationAgentCacheExitOnErr] = strconv.FormatBool(DefaultAgentCacheExitOnErr)
}

if _, ok := pod.ObjectMeta.Annotations[AnnotationAgentInjectDefaultTemplate]; !ok {
pod.ObjectMeta.Annotations[AnnotationAgentInjectDefaultTemplate] = cfg.DefaultTemplate
}

return nil
}

Expand Down
201 changes: 124 additions & 77 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,32 @@ import (
"github.com/stretchr/testify/require"
)

func basicAgentConfig() AgentConfig {
return AgentConfig{
Image: "foobar-image",
Address: "http://foobar:8200",
AuthType: DefaultVaultAuthType,
AuthPath: "test",
Namespace: "test",
RevokeOnShutdown: true,
UserID: "100",
GroupID: "1000",
SameID: DefaultAgentRunAsSameUser,
SetSecurityContext: DefaultAgentSetSecurityContext,
ProxyAddress: "http://proxy:3128",
DefaultTemplate: DefaultTemplateType,
ResourceRequestCPU: DefaultResourceRequestCPU,
ResourceRequestMem: DefaultResourceRequestMem,
ResourceLimitCPU: DefaultResourceLimitCPU,
ResourceLimitMem: DefaultResourceLimitMem,
}
}

func TestInitCanSet(t *testing.T) {
annotations := make(map[string]string)
pod := testPod(annotations)

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "http://proxy:3128",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -56,11 +73,12 @@ func TestInitDefaults(t *testing.T) {
annotations := make(map[string]string)
pod := testPod(annotations)

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "", "",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
agentConfig.Image = ""
agentConfig.UserID = ""
agentConfig.GroupID = ""
agentConfig.ProxyAddress = ""

err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -91,11 +109,9 @@ func TestInitError(t *testing.T) {
annotations := make(map[string]string)
pod := testPod(annotations)

agentConfig := AgentConfig{
"image", "", DefaultVaultAuthType, "authPath", "namespace", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
agentConfig.Address = ""

err := Init(pod, agentConfig)
if err == nil {
t.Error("expected error no address, got none")
Expand Down Expand Up @@ -156,11 +172,7 @@ func TestSecretAnnotationsWithPreserveCaseSensitivityFlagOff(t *testing.T) {
pod := testPod(annotation)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -208,11 +220,7 @@ func TestSecretAnnotationsWithPreserveCaseSensitivityFlagOn(t *testing.T) {
pod := testPod(annotation)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -296,11 +304,7 @@ func TestSecretLocationFileAnnotations(t *testing.T) {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -382,11 +386,7 @@ func TestSecretTemplateAnnotations(t *testing.T) {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -443,11 +443,7 @@ func TestTemplateShortcuts(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pod := testPod(tt.annotations)
agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -516,11 +512,7 @@ func TestSecretMixedTemplatesAnnotations(t *testing.T) {
}
for _, tt := range tests {
pod := testPod(tt.annotations)
agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "", "",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -581,11 +573,7 @@ func TestSecretTemplateFileAnnotations(t *testing.T) {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "", "",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -637,11 +625,7 @@ func TestSecretCommandAnnotations(t *testing.T) {

for _, tt := range tests {
pod := testPod(tt.annotations)
agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -770,12 +754,7 @@ func TestCouldErrorAnnotations(t *testing.T) {
annotations := map[string]string{tt.key: tt.value}
pod := testPod(annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand All @@ -792,12 +771,7 @@ func TestCouldErrorAnnotations(t *testing.T) {

func TestInitEmptyPod(t *testing.T) {
var pod *corev1.Pod

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err == nil {
t.Errorf("got no error, should have")
Expand All @@ -823,11 +797,7 @@ func TestVaultNamespaceAnnotation(t *testing.T) {
pod := testPod(annotation)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"foobar-image", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand Down Expand Up @@ -984,11 +954,7 @@ func TestAuthConfigAnnotations(t *testing.T) {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := AgentConfig{
"", "http://foobar:8200", DefaultVaultAuthType, "test", "test", true, "100", "1000",
DefaultAgentRunAsSameUser, DefaultAgentSetSecurityContext, "",
DefaultResourceRequestCPU, DefaultResourceRequestMem, DefaultResourceLimitCPU, DefaultResourceLimitMem,
}
agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
Expand All @@ -1002,3 +968,84 @@ func TestAuthConfigAnnotations(t *testing.T) {
require.Equal(t, agent.Vault.AuthConfig, tt.expectedAuthConfig, "expected AuthConfig %v, got %v", tt.expectedAuthConfig, agent.Vault.AuthConfig)
}
}

func TestDefaultTemplateOverride(t *testing.T) {
tests := []struct {
annotations map[string]string
expectedValue string
expectedErr bool
}{
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "json",
},
"json",
false,
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "JSON",
},
"json",
false,
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "map",
},
"map",
false,
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "MAP",
},
"map",
false,
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "foobar",
},
"",
true,
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "jsn",
},
"",
true,
},
{
map[string]string{
"vault.hashicorp.com/agent-inject-default-template": "",
},
"",
true,
},
}

for _, tt := range tests {
pod := testPod(tt.annotations)
var patches []*jsonpatch.JsonPatchOperation

agentConfig := basicAgentConfig()
err := Init(pod, agentConfig)
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}

agent, err := New(pod, patches)
if err != nil && !tt.expectedErr {
t.Errorf("got error, shouldn't have: %s", err)
} else if err == nil && tt.expectedErr {
t.Error("got no error, should have")
}

if !tt.expectedErr {
require.Equal(t, agent.DefaultTemplate, tt.expectedValue,
"expected %v, got %v", tt.expectedValue, agent.DefaultTemplate)
}
}
}
Loading

0 comments on commit a9f26ad

Please sign in to comment.