Skip to content

Commit

Permalink
Add annotation to copy volume mounts from existing container (hashico…
Browse files Browse the repository at this point in the history
…rp#212)

* Add annotation to copy volumeMounts from container

Add test

Add copy volume mount test

Extract copyVolumeMount logic

Signed-off-by: Pierce Bartine <piercebartine@gmail.com>

* Add handler test for CopyVolumeMounts
  • Loading branch information
pbar1 authored Jan 26, 2021
1 parent 442923e commit 379869c
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 2 deletions.
23 changes: 23 additions & 0 deletions agent-inject/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ type Agent struct {
// ExtraSecret is the Kubernetes secret to mount as a volume in the Vault agent container
// which can be referenced by the Agent config for secrets. Mounted at /vault/custom/
ExtraSecret string

// CopyVolumeMounts is the name of the container in the Pod whose volume mounts
// should be copied into the Vault Agent init and/or sidecar containers.
CopyVolumeMounts string
}

type Secret struct {
Expand Down Expand Up @@ -234,6 +238,7 @@ func New(pod *corev1.Pod, patches []*jsonpatch.JsonPatchOperation) (*Agent, erro
ServiceAccountPath: saPath,
Status: pod.Annotations[AnnotationAgentStatus],
ExtraSecret: pod.Annotations[AnnotationAgentExtraSecret],
CopyVolumeMounts: pod.Annotations[AnnotationAgentCopyVolumeMounts],
Vault: Vault{
Address: pod.Annotations[AnnotationVaultService],
AuthPath: pod.Annotations[AnnotationVaultAuthPath],
Expand Down Expand Up @@ -541,3 +546,21 @@ func (a *Agent) vaultCliFlags() []string {

return flags
}

// copyVolumeMounts copies the specified container or init container's volume mounts.
// Ignores any Kubernetes service account token mounts.
func (a *Agent) copyVolumeMounts(targetContainerName string) []corev1.VolumeMount {
// Deep copy the pod spec so append doesn't mutate the original containers slice
podSpec := a.Pod.Spec.DeepCopy()
copiedVolumeMounts := make([]corev1.VolumeMount, 0)
for _, container := range append(podSpec.Containers, podSpec.InitContainers...) {
if container.Name == targetContainerName {
for _, volumeMount := range container.VolumeMounts {
if !strings.Contains(strings.ToLower(volumeMount.MountPath), "serviceaccount") {
copiedVolumeMounts = append(copiedVolumeMounts, volumeMount)
}
}
}
}
return copiedVolumeMounts
}
5 changes: 5 additions & 0 deletions agent-inject/agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ func testPod(annotations map[string]string) *corev1.Pod {
Name: "foobar",
MountPath: "serviceaccount/somewhere",
},
{
Name: "tobecopied",
MountPath: "/etc/somewhereelse",
ReadOnly: false,
},
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions agent-inject/agent/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ const (

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

// AnnotationAgentCopyVolumeMounts is the name of the container or init container
// in the Pod whose volume mounts should be copied onto the Vault Agent init and
// sidecar containers. Ignores any Kubernetes service account token mounts.
AnnotationAgentCopyVolumeMounts = "vault.hashicorp.com/agent-copy-volume-mounts"
)

type AgentConfig struct {
Expand Down
4 changes: 4 additions & 0 deletions agent-inject/agent/container_init_sidecar.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ func (a *Agent) ContainerInitSidecar() (corev1.Container, error) {
})
}

if a.CopyVolumeMounts != "" {
volumeMounts = append(volumeMounts, a.copyVolumeMounts(a.CopyVolumeMounts)...)
}

arg := DefaultContainerArg

if a.ConfigMapName != "" {
Expand Down
4 changes: 4 additions & 0 deletions agent-inject/agent/container_sidecar.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (a *Agent) ContainerSidecar() (corev1.Container, error) {
})
}

if a.CopyVolumeMounts != "" {
volumeMounts = append(volumeMounts, a.copyVolumeMounts(a.CopyVolumeMounts)...)
}

arg := DefaultContainerArg

if a.ConfigMapName != "" {
Expand Down
12 changes: 10 additions & 2 deletions agent-inject/agent/container_sidecar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ func TestContainerSidecarVolume(t *testing.T) {

// Test adding an extra secret from Kube secrets for reference by Agent config
fmt.Sprintf("%s", AnnotationAgentExtraSecret): "extrasecret",

// Test copying volume mounts from an existing container in the Pod to the agent container
fmt.Sprintf("%s", AnnotationAgentCopyVolumeMounts): "foobar",
}

pod := testPod(annotations)
Expand All @@ -48,8 +51,8 @@ func TestContainerSidecarVolume(t *testing.T) {

container, err := agent.ContainerSidecar()

// One token volume mount, one config volume mount and two secrets volume mounts
require.Equal(t, 5, len(container.VolumeMounts))
// One token volume mount, one config volume mount, two secrets volume mounts, and one mount copied from main container
require.Equal(t, 6, len(container.VolumeMounts))

require.Equal(
t,
Expand Down Expand Up @@ -79,6 +82,11 @@ func TestContainerSidecarVolume(t *testing.T) {
MountPath: extraSecretVolumePath,
ReadOnly: true,
},
corev1.VolumeMount{
Name: "tobecopied",
MountPath: "/etc/somewhereelse",
ReadOnly: false,
},
},
container.VolumeMounts,
)
Expand Down
59 changes: 59 additions & 0 deletions agent-inject/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ func TestHandlerHandle(t *testing.T) {
},
}

basicSpecWithMounts := *basicSpec.DeepCopy()
basicSpecWithMounts.InitContainers[0].VolumeMounts = append(basicSpecWithMounts.InitContainers[0].VolumeMounts, corev1.VolumeMount{
Name: "tobecopied",
MountPath: "/etc/somewhereelse",
})

cases := []struct {
Name string
Handler Handler
Expand Down Expand Up @@ -499,6 +505,59 @@ func TestHandlerHandle(t *testing.T) {
},
},
},

{
"copy volume mounts pod injection",
Handler{VaultAddress: "https://vault:8200", VaultAuthPath: "kubernetes", ImageVault: "vault", Log: hclog.Default().Named("handler")},
v1beta1.AdmissionRequest{
Namespace: "test",
Object: encodeRaw(t, &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
agent.AnnotationAgentInject: "true",
agent.AnnotationVaultRole: "demo",
agent.AnnotationAgentCopyVolumeMounts: "web-init",
},
},
Spec: basicSpecWithMounts,
}),
},
"",
[]jsonpatch.JsonPatchOperation{
{
Operation: "add",
Path: "/spec/volumes",
},
{
Operation: "add",
Path: "/spec/volumes/-",
},
{
Operation: "add",
Path: "/spec/volumes",
},
{
Operation: "add",
Path: "/spec/containers/0/volumeMounts/-",
},
{
Operation: "add",
Path: "/spec/initContainers/-",
},
{
Operation: "add",
Path: "/spec/initContainers/0/volumeMounts/-",
},
{
Operation: "add",
Path: "/spec/containers/-",
},
{
Operation: "add",
Path: "/metadata/annotations/" + agent.EscapeJSONPointer(agent.AnnotationAgentStatus),
},
},
},
}

for _, tt := range cases {
Expand Down

0 comments on commit 379869c

Please sign in to comment.