diff --git a/src/internal/agent/hooks/pods.go b/src/internal/agent/hooks/pods.go index 1ee02f899a..a7f927fade 100644 --- a/src/internal/agent/hooks/pods.go +++ b/src/internal/agent/hooks/pods.go @@ -114,6 +114,19 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } + // update the image host for each volume that contains a "image" reference + for idx, volume := range pod.Spec.Volumes { + if volume.Image != nil { + path := fmt.Sprintf("/spec/volume/%d/image/reference", idx) + replacement, err := transform.ImageTransformHost(registryURL, volume.Image.Reference) + if err != nil { + return nil, err + } + updatedAnnotations[getImageAnnotationKey(volume.Image.Reference)] = volume.Image.Reference + patches = append(patches, operations.ReplacePatchOperation(path, replacement)) + } + } + patches = append(patches, getLabelPatch(pod.Labels)) patches = append(patches, operations.ReplacePatchOperation("/metadata/annotations", updatedAnnotations)) diff --git a/src/internal/agent/hooks/pods_test.go b/src/internal/agent/hooks/pods_test.go index 42ddaab8fa..b20ab91d3b 100644 --- a/src/internal/agent/hooks/pods_test.go +++ b/src/internal/agent/hooks/pods_test.go @@ -60,6 +60,24 @@ func TestPodMutationWebhook(t *testing.T) { }, }, }, + Volumes: []corev1.Volume{ + {Name: "config-map", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "not-mutate-cm", + }, + }, + }, + }, + {Name: "image", + VolumeSource: corev1.VolumeSource{ + Image: &corev1.ImageVolumeSource{ + Reference: "quay.io/crio/artifact:v1", + }, + }, + }, + }, }, }), patch: []operations.PatchOperation{ @@ -79,6 +97,10 @@ func TestPodMutationWebhook(t *testing.T) { "/spec/containers/0/image", "127.0.0.1:31999/library/nginx:latest-zarf-3793515731", ), + operations.ReplacePatchOperation( + "/spec/volume/1/image/reference", + "127.0.0.1:31999/crio/artifact:v1-zarf-2568457951", + ), operations.ReplacePatchOperation( "/metadata/labels", map[string]string{ @@ -89,10 +111,11 @@ func TestPodMutationWebhook(t *testing.T) { operations.ReplacePatchOperation( "/metadata/annotations", map[string]string{ - "zarf.dev/original-image-nginx": "nginx", - "zarf.dev/original-image-alpine": "alpine", - "zarf.dev/original-image-different": "busybox", - "should-be": "mutated", + "should-be": "mutated", + "zarf.dev/original-image-nginx": "nginx", + "zarf.dev/original-image-alpine": "alpine", + "zarf.dev/original-image-different": "busybox", + "zarf.dev/original-image-quay.io/crio/artifact:v1": "quay.io/crio/artifact:v1", }, ), }, diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index 2a25239189..73537ab0a7 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -8,7 +8,6 @@ import ( "context" "errors" "fmt" - "github.com/zarf-dev/zarf/src/pkg/logger" "os" "path/filepath" "regexp" @@ -16,6 +15,8 @@ import ( "strings" "time" + "github.com/zarf-dev/zarf/src/pkg/logger" + "github.com/defenseunicorns/pkg/helpers/v2" "github.com/goccy/go-yaml" "github.com/google/go-containerregistry/pkg/crane" @@ -462,6 +463,11 @@ func appendToImageMap(imgMap map[string]bool, pod corev1.PodSpec) map[string]boo for _, container := range pod.EphemeralContainers { imgMap[container.Image] = true } + for _, volume := range pod.Volumes { + if volume.Image != nil { + imgMap[volume.Image.Reference] = true + } + } return imgMap } diff --git a/src/pkg/packager/prepare_test.go b/src/pkg/packager/prepare_test.go index ea244d8a52..e91fe579ab 100644 --- a/src/pkg/packager/prepare_test.go +++ b/src/pkg/packager/prepare_test.go @@ -69,6 +69,21 @@ func TestFindImages(t *testing.T) { }, }, }, + { + name: "pod volume image", + cfg: &types.PackagerConfig{ + CreateOpts: types.ZarfCreateOptions{ + BaseDir: "./testdata/find-images/pod-volume-image", + }, + }, + expectedImages: map[string][]string{ + "baseline": { + "ghcr.io/zarf-dev/zarf/agent:v0.38.1", + "quay.io/crio/artifact:v1", + "ghcr.io/zarf-dev/zarf/agent:sha256-f8b1c2f99349516ae1bd0711a19697abcc41555076b0ae90f1a70ca6b50dcbd8.sig", + }, + }, + }, { name: "image not found", cfg: &types.PackagerConfig{ diff --git a/src/pkg/packager/testdata/find-images/pod-volume-image/deployment.yaml b/src/pkg/packager/testdata/find-images/pod-volume-image/deployment.yaml new file mode 100644 index 0000000000..894559d603 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/pod-volume-image/deployment.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: agent +spec: + selector: + matchLabels: + app: agent + template: + metadata: + labels: + app: agent + spec: + containers: + - name: agent + image: ghcr.io/zarf-dev/zarf/agent:v0.38.1 + volume: + - name: config-volume + configMap: + name: special-config + - name: image + image: + reference: quay.io/crio/artifact:v1 + pullPolicy: IfNotPresent diff --git a/src/pkg/packager/testdata/find-images/pod-volume-image/zarf.yaml b/src/pkg/packager/testdata/find-images/pod-volume-image/zarf.yaml new file mode 100644 index 0000000000..7cfe15f6ea --- /dev/null +++ b/src/pkg/packager/testdata/find-images/pod-volume-image/zarf.yaml @@ -0,0 +1,12 @@ +kind: ZarfPackageConfig +metadata: + name: pod-volume-image + version: 1.0.0 +components: + - name: baseline + required: true + manifests: + - name: pod-volume-image + namespace: default + files: + - deployment.yaml