Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add agent-inject-containers annotation #163

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,22 @@ func (a *Agent) Patch() ([]byte, error) {
"/spec/volumes")...)
}

//Add Volume Mounts
//Add Volume Mounts to desired containers
raw, ok := a.Pod.Annotations[AnnotationAgentInjectContainers];
if !ok {
return patches, fmt.Errorf("vault.hashicorp.com/agent-inject-containers annotation not found")
}

names := make(map[string]struct{})
for _, name := range strings.Split(raw, ",") {
names[name] = struct{}{}
}
Comment on lines +387 to +395
Copy link
Contributor

@jasonodonnell jasonodonnell Aug 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking this code isn't necessary because we could extend the Agent struct to have a Containers []string type, then populate that using the Init function. If the slice is empty, apply to all containers, if it's not, only mount to containers that match.


for i, container := range a.Pod.Spec.Containers {
if _, ok := names[container.Name]; !ok {
continue
}

a.Patches = append(a.Patches, addVolumeMounts(
container.VolumeMounts,
a.ContainerVolumeMounts(),
Expand Down
16 changes: 16 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ const (
// If not provided (the default), no command is executed.
AnnotationAgentInjectCommand = "vault.hashicorp.com/agent-inject-command"

// AnnotationAgentInjectContainers is the key of the annotation that controls
// in which containers the secrets volume should be mounted. Multiple containers can
// be specificied in a comma-separated list. If not provided, the secrets volume will
// be mounted in all containers in the pod.
AnnotationAgentInjectContainers = "vault.hashicorp.com/agent-inject-containers"

// AnnotationAgentImage is the name of the Vault docker image to use.
AnnotationAgentImage = "vault.hashicorp.com/agent-image"

Expand Down Expand Up @@ -324,6 +330,16 @@ func Init(pod *corev1.Pod, cfg AgentConfig) error {
pod.ObjectMeta.Annotations[AnnotationAgentCacheUseAutoAuthToken] = DefaultAgentCacheUseAutoAuthToken
}

// If the AnnotationAgentInjectContainers annotation is not set, default to all containers
if _, ok := pod.ObjectMeta.Annotations[AnnotationAgentInjectContainers]; !ok {
containerNames := make([]string, len(pod.Spec.Containers))
for i, v := range pod.Spec.Containers {
containerNames[i] = v.Name
}

pod.ObjectMeta.Annotations[AnnotationAgentInjectContainers] = strings.Join(containerNames, ",")
}

return nil
}

Expand Down
73 changes: 73 additions & 0 deletions agent-inject/agent/annotations_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package agent

import (
"encoding/json"
"fmt"
"reflect"
"strconv"
Expand Down Expand Up @@ -793,3 +794,75 @@ func Test_runAsSameID(t *testing.T) {
})
}
}

func TestInjectContainers(t *testing.T) {
expectedPatch := "{\"op\":\"add\",\"path\":\"/spec/containers/0/volumeMounts/-\",\"value\":{\"mountPath\":\"/vault/secrets\",\"name\":\"vault-secrets\"}}"

tests := []struct {
name string
annotations map[string]string
expected string
hasPatch bool
Comment on lines +802 to +805
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: gofmt needs to be run on this file.

}{
{
name: "No InjectContainers annotation",
annotations: map[string]string{},
expected: "foobar",
hasPatch: true,
},
{
name: "InjectContainers annotation with container name",
annotations: map[string]string{AnnotationAgentInjectContainers: "baz"},
expected: "baz",
hasPatch: false,
},
Comment on lines +813 to +818
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need another test here for multiple containers being selected via this annotation.

{
name: "Empty InjectContainers annotation",
annotations: map[string]string{AnnotationAgentInjectContainers: ""},
expected: "",
hasPatch: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pod := testPod(tt.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, shouldn't have: %s", err)
}

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

patch, err := agent.Patch()
if err != nil {
t.Errorf("got error, shouldn't have: %s", err)
}

require.Equal(t, pod.Annotations[AnnotationAgentInjectContainers], tt.expected)

var actual []jsonpatch.JsonPatchOperation
json.Unmarshal(patch, &actual)

// Ensure the container patch is present if it is expected
hasPatch := false
for _, p := range actual {
if p.Json() == expectedPatch {
hasPatch = true
}
}

require.Equal(t, hasPatch, tt.hasPatch)
})
}
}