Skip to content

Commit 9d626f4

Browse files
ybettank8s-ci-robot
authored andcommitted
Remove intermediate image when we have both build and sign.
When signing is added to a Module CR after an initial unsigned build, the operator entered an infinite rebuild loop because the sign pod expected an intermediate image tag (containerImage:ns_name_kmm_unsigned) that was never populated by the original build. Changes: - Remove intermediate image concept (internal/buildsign/resource/common.go) - makeBuildTemplate: always pushes directly to mld.ContainerImage; no longer redirects to an intermediate tag when sign is defined - makeSignTemplate: when build is also present, uses mld.ContainerImage as the unsigned source - sign overwrites the final image in place - Remove IntermediateImageName (internal/module/helper.go) - function is now unused Flow before vs. after: Build (with sign): pushed to image:ns_name_kmm_unsigned -> pushes to image Sign (with build): read from image:ns_name_kmm_unsigned -> reads from image, overwrites in place With this change, adding signing to an existing built module works without a rebuild: the sign pod finds the already-pushed image at the correct tag and signs it directly. The intermediate image was initially required because we didn't have the MIC and MBSC objects to sync the build/sign jobs and the existence of the image in the image registry was used as a proof that the sign is done. This is not required anymore since MIC is syncing the sign job only once the build job has succeed. Signed-off-by: Yoni Bettan <yonibettan@gmail.com>
1 parent 7f06f37 commit 9d626f4

5 files changed

Lines changed: 47 additions & 51 deletions

File tree

docs/mkdocs/documentation/secure_boot.md

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,19 +163,11 @@ spec:
163163
The YAML below should build a new container image using the
164164
[source code from the repo](https://github.com/kubernetes-sigs/kernel-module-management/tree/main/ci/kmm-kmod) (this
165165
kernel module does nothing useful but provides a good example).
166-
The image produced is saved back in the registry with a temporary name, and this temporary image is then signed using
167-
the parameters in the `sign` section.
168166
169-
The temporary image name is based on the final image name and is set to be
170-
`<containerImage>:<tag>-<namespace>_<module name>_kmm_unsigned`.
171-
172-
For example, given the YAML below KMM would build an image named
173-
`quay.io/chrisp262/minimal-driver:final-default_example-module_kmm_unsigned` containing the build but unsigned kmods,
174-
and push it to the registry.
175-
Then it would create a second image, `quay.io/chrisp262/minimal-driver:final` containing the signed kmods.
176-
It is this second image that will be loaded by the DaemonSet and will deploy the kmods to the cluster nodes.
177-
178-
Once it is signed the temporary image can be safely deleted from the registry (it will be rebuilt if needed).
167+
The build pod pushes the unsigned image directly to `containerImage`.
168+
The sign pod then reads from that same image, signs the kernel modules in place, and overwrites `containerImage` with
169+
the signed result.
170+
The image loaded by the DaemonSet onto cluster nodes is the final signed image at `containerImage`.
179171

180172

181173
## Example

internal/buildsign/resource/common.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,7 @@ func (rm *resourceManager) getResources(ctx context.Context, namespace string, l
261261
func (rm *resourceManager) makeBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, owner metav1.Object,
262262
pushImage bool) (metav1.Object, error) {
263263

264-
// if build AND sign are specified, then we will build an intermediate image
265-
// and let sign produce the one specified in its targetImage
266-
containerImage := mld.ContainerImage
267-
if module.ShouldBeSigned(mld) {
268-
containerImage = module.IntermediateImageName(mld.Name, mld.Namespace, containerImage)
269-
}
270-
271-
buildSpec := rm.buildSpec(mld, containerImage, pushImage)
264+
buildSpec := rm.buildSpec(mld, mld.ContainerImage, pushImage)
272265
buildSpecHash, err := rm.getBuildHashAnnotationValue(
273266
ctx,
274267
mld.Build.DockerfileConfigMap.Name,
@@ -310,13 +303,8 @@ func (rm *resourceManager) makeSignTemplate(ctx context.Context, mld *api.Module
310303
DirName: mld.Modprobe.DirName,
311304
}
312305

313-
imageToSign := ""
314306
if module.ShouldBeBuilt(mld) {
315-
imageToSign = module.IntermediateImageName(mld.Name, mld.Namespace, mld.ContainerImage)
316-
}
317-
318-
if imageToSign != "" {
319-
td.UnsignedImage = imageToSign
307+
td.UnsignedImage = mld.ContainerImage
320308
} else if signConfig.UnsignedImage != "" {
321309
td.UnsignedImage = signConfig.UnsignedImage
322310
} else {

internal/buildsign/resource/common_test.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ var _ = Describe("makeBuildTemplate", func() {
411411
Expect(actualPod.Spec.Containers[0].Image).To(Equal("some-build-image:" + customTag))
412412
})
413413

414-
It("should add the kmm_unsigned suffix to the target image if sign is defined", func() {
414+
It("should use the final container image as the build destination even when sign is defined", func() {
415415
ctx := context.Background()
416416

417417
mld := api.ModuleLoaderData{
@@ -429,8 +429,6 @@ var _ = Describe("makeBuildTemplate", func() {
429429
KernelNormalizedVersion: kernelNormalizedVersion,
430430
}
431431

432-
expectedImageName := mld.ContainerImage + ":" + mld.Namespace + "_" + mld.Name + "_kmm_unsigned"
433-
434432
gomock.InOrder(
435433
mbao.EXPECT().ApplyBuildArgOverrides(buildArgs, defaultBuildArgs),
436434
clnt.EXPECT().Get(ctx, types.NamespacedName{Name: dockerfileConfigMap.Name, Namespace: mld.Namespace}, gomock.Any()).DoAndReturn(
@@ -447,7 +445,7 @@ var _ = Describe("makeBuildTemplate", func() {
447445

448446
Expect(err).NotTo(HaveOccurred())
449447
Expect(actualPod.Spec.Containers[0].Args).To(ContainElement("--destination"))
450-
Expect(actualPod.Spec.Containers[0].Args).To(ContainElement(expectedImageName))
448+
Expect(actualPod.Spec.Containers[0].Args).To(ContainElement(image))
451449
})
452450
})
453451

@@ -896,6 +894,45 @@ COPY --from=signimage /opt/modules /modules
896894
[]string{"source-extract"},
897895
),
898896
)
897+
898+
It("should use the container image as source when build is also defined", func() {
899+
GinkgoT().Setenv("RELATED_IMAGE_BUILD", buildImage)
900+
GinkgoT().Setenv("RELATED_IMAGE_SIGN", "some-sign-image:some-tag")
901+
902+
ctx := context.Background()
903+
mld.Build = &kmmv1beta1.Build{}
904+
mld.Sign = &kmmv1beta1.Sign{
905+
KeySecret: &v1.LocalObjectReference{Name: "securebootkey"},
906+
CertSecret: &v1.LocalObjectReference{Name: "securebootcert"},
907+
FilesToSign: []string{"/modules/test.ko"},
908+
}
909+
mld.ContainerImage = unsignedImage
910+
mld.RegistryTLS = &kmmv1beta1.TLSOptions{}
911+
912+
gomock.InOrder(
913+
clnt.EXPECT().Get(ctx, types.NamespacedName{Name: mld.Sign.KeySecret.Name, Namespace: mld.Namespace}, gomock.Any()).DoAndReturn(
914+
func(_ interface{}, _ interface{}, secret *v1.Secret, _ ...ctrlclient.GetOption) error {
915+
secret.Data = privateSignData
916+
return nil
917+
},
918+
),
919+
clnt.EXPECT().Get(ctx, types.NamespacedName{Name: mld.Sign.CertSecret.Name, Namespace: mld.Namespace}, gomock.Any()).DoAndReturn(
920+
func(_ interface{}, _ interface{}, secret *v1.Secret, _ ...ctrlclient.GetOption) error {
921+
secret.Data = publicSignData
922+
return nil
923+
},
924+
),
925+
)
926+
927+
actual, err := rm.makeSignTemplate(ctx, &mld, mld.Owner, true)
928+
Expect(err).NotTo(HaveOccurred())
929+
actualPod, ok := actual.(*v1.Pod)
930+
Expect(ok).To(BeTrue())
931+
932+
// The Dockerfile annotation should use the container image (not an intermediate image) as the
933+
// unsigned source when build is also present.
934+
Expect(actualPod.Annotations["dockerfile"]).To(ContainSubstring(unsignedImage))
935+
})
899936
})
900937
var _ = Describe("resourceLabels", func() {
901938

internal/module/helper.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,8 @@ func AppendToTag(name string, tag string) string {
3535
return name + separator + tag
3636
}
3737

38-
// IntermediateImageName returns the image name of the pre-signed module image name
39-
func IntermediateImageName(name, namespace, targetImage string) string {
40-
return AppendToTag(targetImage, namespace+"_"+name+"_kmm_unsigned")
41-
}
42-
4338
// ShouldBeBuilt indicates whether the specified ModuleLoaderData of the
4439
// Module should be built or not.
4540
func ShouldBeBuilt(mld *api.ModuleLoaderData) bool {
4641
return mld.Build != nil
4742
}
48-
49-
// ShouldBeSigned indicates whether the specified ModuleLoaderData of the
50-
// Module should be signed or not.
51-
func ShouldBeSigned(mld *api.ModuleLoaderData) bool {
52-
return mld.Sign != nil
53-
}

internal/module/helper_test.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,3 @@ var _ = Describe("AppendToTag", func() {
2828
)
2929
})
3030
})
31-
32-
var _ = Describe("IntermediateImageName", func() {
33-
It("should add the kmm_unsigned suffix to the target image name", func() {
34-
Expect(
35-
IntermediateImageName("module-name", "test-namespace", "some-image-name"),
36-
).To(
37-
Equal("some-image-name:test-namespace_module-name_kmm_unsigned"),
38-
)
39-
})
40-
})

0 commit comments

Comments
 (0)