From e501d31cfb2ad76f4af88941b757b070ec281b23 Mon Sep 17 00:00:00 2001 From: Danny Joyce Date: Mon, 14 Dec 2020 16:41:50 -0500 Subject: [PATCH] add notary signing to rebased images --- cmd/rebase/main.go | 22 ++++- pkg/apis/build/v1alpha1/build_pod.go | 29 ++++--- pkg/apis/build/v1alpha1/build_pod_test.go | 101 ++++++++++++++++++---- 3 files changed, 123 insertions(+), 29 deletions(-) diff --git a/cmd/rebase/main.go b/cmd/rebase/main.go index 9e029fee6..7fe7fdaf0 100644 --- a/cmd/rebase/main.go +++ b/cmd/rebase/main.go @@ -1,15 +1,18 @@ package main import ( + "bytes" "flag" "log" "os" "path/filepath" + "github.com/BurntSushi/toml" "github.com/buildpacks/imgutil/remote" "github.com/buildpacks/lifecycle" "github.com/buildpacks/lifecycle/cmd" "github.com/pkg/errors" + "github.com/shurcooL/go/ioutil" "github.com/pivotal/kpack/pkg/buildchange" "github.com/pivotal/kpack/pkg/dockercreds" @@ -24,6 +27,7 @@ var ( runImage = flag.String("run-image", os.Getenv("RUN_IMAGE"), "The new run image to rebase") lastBuiltImage = flag.String("last-built-image", os.Getenv("LAST_BUILT_IMAGE"), "The previous image to rebase") buildChanges = flag.String("build-changes", os.Getenv("BUILD_CHANGES"), "JSON string of build changes and their reason") + reportFilePath = flag.String("report", os.Getenv("REPORT_FILE_PATH"), "The location at which to write the report.toml") dockerCredentials flaghelpers.CredentialsFlags dockerCfgCredentials flaghelpers.CredentialsFlags @@ -97,6 +101,20 @@ func rebase(tags []string, logger *log.Logger) error { rebaser := lifecycle.Rebaser{ Logger: cmd.DefaultLogger, } - _, err = rebaser.Rebase(appImage, newBaseImage, tags[1:]) - return err + report, err := rebaser.Rebase(appImage, newBaseImage, tags[1:]) + if err != nil { + return err + } + + if *reportFilePath == "" { + return nil + } + + buf := &bytes.Buffer{} + err = toml.NewEncoder(buf).Encode(report) + if err != nil { + return err + } + + return ioutil.WriteFile(*reportFilePath, buf) } diff --git a/pkg/apis/build/v1alpha1/build_pod.go b/pkg/apis/build/v1alpha1/build_pod.go index c6fe92c55..912aebb79 100644 --- a/pkg/apis/build/v1alpha1/build_pod.go +++ b/pkg/apis/build/v1alpha1/build_pod.go @@ -31,8 +31,8 @@ const ( imagePullSecretsDirName = "image-pull-secrets-dir" builderPullSecretsDirName = "builder-pull-secrets-dir" - notaryDirName = "notary-dir" - reportDirName = "report-dir" + notaryDirName = "notary-dir" + reportDirName = "report-dir" envVarBuildChanges = "BUILD_CHANGES" ) @@ -456,15 +456,19 @@ func (b *Build) rebasePod(secrets []corev1.Secret, config BuildPodImages, buildP NodeSelector: map[string]string{ "kubernetes.io/os": "linux", }, - Volumes: secretVolumes, + Volumes: append( + secretVolumes, + corev1.Volume{ + Name: reportDirName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + b.notarySecretVolume(), + ), RestartPolicy: corev1.RestartPolicyNever, Containers: []corev1.Container{ - { - Name: "completion", - Image: config.CompletionImage, - ImagePullPolicy: corev1.PullIfNotPresent, - Resources: b.Spec.Resources, - }, + b.completionContainer(config, secretArgs, secretVolumeMounts), }, InitContainers: []corev1.Container{ { @@ -476,7 +480,10 @@ func (b *Build) rebasePod(secrets []corev1.Secret, config BuildPodImages, buildP "--run-image", buildPodBuilderConfig.RunImage, "--last-built-image", - b.Spec.LastBuild.Image), + b.Spec.LastBuild.Image, + "--report", + "/var/report/report.toml", + ), secretArgs, b.Spec.Tags, ), @@ -488,7 +495,7 @@ func (b *Build) rebasePod(secrets []corev1.Secret, config BuildPodImages, buildP }, ImagePullPolicy: corev1.PullIfNotPresent, WorkingDir: "/workspace", - VolumeMounts: secretVolumeMounts, + VolumeMounts: append(secretVolumeMounts, reportVolume), }, }, }, diff --git a/pkg/apis/build/v1alpha1/build_pod_test.go b/pkg/apis/build/v1alpha1/build_pod_test.go index d117e8d49..2b092e363 100644 --- a/pkg/apis/build/v1alpha1/build_pod_test.go +++ b/pkg/apis/build/v1alpha1/build_pod_test.go @@ -744,13 +744,13 @@ func testBuildPod(t *testing.T, when spec.G, it spec.S) { }) when("creating a rebase pod", func() { - it("creates a pod just to rebase", func() { - build.Annotations = map[string]string{ - v1alpha1.BuildReasonAnnotation: v1alpha1.BuildReasonStack, - v1alpha1.BuildChangesAnnotation: "some-stack-change", - "some/annotation": "to-pass-through", - } + build.Annotations = map[string]string{ + v1alpha1.BuildReasonAnnotation: v1alpha1.BuildReasonStack, + v1alpha1.BuildChangesAnnotation: "some-stack-change", + "some/annotation": "to-pass-through", + } + it("creates a pod just to rebase", func() { pod, err := build.BuildPod(config, secrets, buildPodBuilderConfig) require.NoError(t, err) @@ -801,6 +801,18 @@ func testBuildPod(t *testing.T, when spec.G, it spec.S) { }, }, }, + { + Name: "report-dir", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "notary-dir", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, }, RestartPolicy: corev1.RestartPolicyNever, Containers: []corev1.Container{ @@ -822,6 +834,8 @@ func testBuildPod(t *testing.T, when spec.G, it spec.S) { "builderregistry.io/run", "--last-built-image", build.Spec.LastBuild.Image, + "--report", + "/var/report/report.toml", "-basic-docker=docker-secret-1=acr.io", "-dockerconfig=docker-secret-2", "-dockercfg=docker-secret-3", @@ -848,11 +862,63 @@ func testBuildPod(t *testing.T, when spec.G, it spec.S) { Name: "secret-volume-docker-secret-3", MountPath: "/var/build-secrets/docker-secret-3", }, + { + Name: "report-dir", + MountPath: "/var/report", + }, }, }, }, }, pod.Spec) }) + + when("a notary config is present on the build", func() { + it("sets up the completion image to sign the image", func() { + build.Spec.Notary = &v1alpha1.NotaryConfig{ + V1: &v1alpha1.NotaryV1Config{ + URL: "some-notary-url", + SecretRef: v1alpha1.NotarySecretRef{ + Name: "some-notary-secret", + }, + }, + } + + pod, err := build.BuildPod(config, secrets, buildPodBuilderConfig) + require.NoError(t, err) + + require.Equal(t, + []string{ + directExecute, + "completion", + "-notary-v1-url=some-notary-url", + "-basic-docker=docker-secret-1=acr.io", + "-dockerconfig=docker-secret-2", + "-dockercfg=docker-secret-3", + }, + pod.Spec.Containers[0].Args, + ) + + require.Contains(t, pod.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ + Name: "notary-dir", + ReadOnly: true, + MountPath: "/var/notary/v1", + }) + require.Contains(t, pod.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ + Name: "report-dir", + ReadOnly: false, + MountPath: "/var/report", + }) + + require.Contains(t, pod.Spec.Volumes, corev1.Volume{ + Name: "notary-dir", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "some-notary-secret", + }, + }, + }) + }) + }) }) when("a notary config is present on the build", func() { @@ -869,16 +935,19 @@ func testBuildPod(t *testing.T, when spec.G, it spec.S) { pod, err := build.BuildPod(config, secrets, buildPodBuilderConfig) require.NoError(t, err) - require.Equal(t, pod.Spec.Containers[0].Args, []string{ - directExecute, - "completion", - "-notary-v1-url=some-notary-url", - "-basic-git=git-secret-1=https://github.com", - "-ssh-git=git-secret-2=https://bitbucket.com", - "-basic-docker=docker-secret-1=acr.io", - "-dockerconfig=docker-secret-2", - "-dockercfg=docker-secret-3", - }) + require.Equal(t, + []string{ + directExecute, + "completion", + "-notary-v1-url=some-notary-url", + "-basic-git=git-secret-1=https://github.com", + "-ssh-git=git-secret-2=https://bitbucket.com", + "-basic-docker=docker-secret-1=acr.io", + "-dockerconfig=docker-secret-2", + "-dockercfg=docker-secret-3", + }, + pod.Spec.Containers[0].Args, + ) require.Contains(t, pod.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: "notary-dir",