From 7beda65fde6c55ce84e7ba2b718c01cafa3f5faf Mon Sep 17 00:00:00 2001 From: Joseph Petersen Date: Sun, 19 Jan 2025 00:40:18 +0100 Subject: [PATCH] add tag when copying image when sourceRef is using both tag and digest --- pkg/registry/client.go | 2 +- pkg/registry/ecr.go | 6 +++++- pkg/registry/gar.go | 6 +++++- pkg/webhook/image_copier.go | 3 ++- pkg/webhook/image_swapper.go | 15 +++++++++------ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/pkg/registry/client.go b/pkg/registry/client.go index da373e2c..e003d3c7 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -16,7 +16,7 @@ import ( type Client interface { CreateRepository(ctx context.Context, name string) error RepositoryExists() bool - CopyImage(ctx context.Context, src ctypes.ImageReference, srcCreds string, dest ctypes.ImageReference, destCreds string) error + CopyImage(ctx context.Context, src ctypes.ImageReference, srcCreds string, dest ctypes.ImageReference, destCreds string, additionalTag string) error PullImage() error PutImage() error ImageExists(ctx context.Context, ref ctypes.ImageReference) bool diff --git a/pkg/registry/ecr.go b/pkg/registry/ecr.go index c456b5ed..598e3c3e 100644 --- a/pkg/registry/ecr.go +++ b/pkg/registry/ecr.go @@ -186,7 +186,7 @@ func (e *ECRClient) RepositoryExists() bool { panic("implement me") } -func (e *ECRClient) CopyImage(ctx context.Context, srcRef ctypes.ImageReference, srcCreds string, destRef ctypes.ImageReference, destCreds string) error { +func (e *ECRClient) CopyImage(ctx context.Context, srcRef ctypes.ImageReference, srcCreds string, destRef ctypes.ImageReference, destCreds string, additionalTag string) error { src := srcRef.DockerReference().String() dest := destRef.DockerReference().String() app := "skopeo" @@ -199,6 +199,10 @@ func (e *ECRClient) CopyImage(ctx context.Context, srcRef ctypes.ImageReference, "docker://" + dest, } + if len(additionalTag) > 0 { + args = append(args, "--additional-tag", additionalTag) + } + if len(srcCreds) > 0 { args = append(args, "--src-authfile", srcCreds) } else { diff --git a/pkg/registry/gar.go b/pkg/registry/gar.go index c129246b..6e6a3743 100644 --- a/pkg/registry/gar.go +++ b/pkg/registry/gar.go @@ -68,7 +68,7 @@ func (e *GARClient) RepositoryExists() bool { panic("implement me") } -func (e *GARClient) CopyImage(ctx context.Context, srcRef ctypes.ImageReference, srcCreds string, destRef ctypes.ImageReference, destCreds string) error { +func (e *GARClient) CopyImage(ctx context.Context, srcRef ctypes.ImageReference, srcCreds string, destRef ctypes.ImageReference, destCreds string, additionalTag string) error { src := srcRef.DockerReference().String() dest := destRef.DockerReference().String() @@ -89,6 +89,10 @@ func (e *GARClient) CopyImage(ctx context.Context, srcRef ctypes.ImageReference, "docker://" + dest, } + if len(additionalTag) > 0 { + args = append(args, "--additional-tag", additionalTag) + } + if len(creds[1]) > 0 { args = append(args, creds...) } else { diff --git a/pkg/webhook/image_copier.go b/pkg/webhook/image_copier.go index 3f2cbfe3..9bbac9cf 100644 --- a/pkg/webhook/image_copier.go +++ b/pkg/webhook/image_copier.go @@ -16,6 +16,7 @@ type ImageCopier struct { sourcePod *corev1.Pod sourceImageRef ctypes.ImageReference targetImageRef ctypes.ImageReference + additionalTag string imagePullPolicy corev1.PullPolicy imageSwapper *ImageSwapper @@ -135,5 +136,5 @@ func (ic *ImageCopier) taskCopyImage() error { // // or transform registryClient creds into auth compatible form, e.g. // {"auths":{"aws_account_id.dkr.ecr.region.amazonaws.com":{"username":"AWS","password":"..." }}} - return ic.imageSwapper.registryClient.CopyImage(ctx, ic.sourceImageRef, authFile.Name(), ic.targetImageRef, ic.imageSwapper.registryClient.Credentials()) + return ic.imageSwapper.registryClient.CopyImage(ctx, ic.sourceImageRef, authFile.Name(), ic.targetImageRef, ic.imageSwapper.registryClient.Credentials(), ic.additionalTag) } diff --git a/pkg/webhook/image_swapper.go b/pkg/webhook/image_swapper.go index ee2aea96..60d3d987 100644 --- a/pkg/webhook/image_swapper.go +++ b/pkg/webhook/image_swapper.go @@ -147,21 +147,23 @@ func NewImageSwapperWebhook(registryClient registry.Client, imagePullSecretProvi // imageNamesWithDigestOrTag strips the tag from ambiguous image references that have a digest as well (e.g. `image:tag@sha256:123...`). // Such image references are supported by docker but, due to their ambiguity, // explicitly not by containers/image. -func imageNamesWithDigestOrTag(imageName string) (string, error) { +func imageNamesWithDigestOrTag(imageName string) (string, string, error) { ref, err := reference.ParseNormalizedNamed(imageName) if err != nil { - return "", err + return "", "", err } - _, isTagged := ref.(reference.NamedTagged) + nameAndTag, isTagged := ref.(reference.NamedTagged) canonical, isDigested := ref.(reference.Canonical) + tag := "" if isTagged && isDigested { + tag = nameAndTag.Tag() canonical, err = reference.WithDigest(reference.TrimNamed(ref), canonical.Digest()) if err != nil { - return "", err + return "", "", err } imageName = canonical.String() } - return imageName, nil + return imageName, tag, nil } // Mutate replaces the image ref. Satisfies mutating.Mutator interface. @@ -184,7 +186,7 @@ func (p *ImageSwapper) Mutate(ctx context.Context, ar *kwhmodel.AdmissionReview, for _, containerSet := range containerSets { containers := *containerSet for i, container := range containers { - normalizedName, err := imageNamesWithDigestOrTag(container.Image) + normalizedName, tag, err := imageNamesWithDigestOrTag(container.Image) if err != nil { log.Ctx(lctx).Warn().Msgf("unable to normalize source name %s: %v", container.Image, err) continue @@ -222,6 +224,7 @@ func (p *ImageSwapper) Mutate(ctx context.Context, ar *kwhmodel.AdmissionReview, sourcePod: pod, sourceImageRef: srcRef, targetImageRef: targetRef, + additionalTag: tag, imagePullPolicy: container.ImagePullPolicy, imageSwapper: p, context: imageCopierContext,