From 3d211afdaa9e429d2f7bf2c70276f2a93c0a97ed Mon Sep 17 00:00:00 2001 From: pxp928 Date: Thu, 14 Apr 2022 09:53:23 -0400 Subject: [PATCH] [TEP-0089] - Phase 1 Signed TaskRun Results Signed-off-by: pxp928 --- docs/spire.md | 2 +- pkg/apis/config/feature_flags.go | 3 + pkg/pod/pod.go | 1 + pkg/pod/pod_test.go | 169 +++++++++++++++++++++++++++++++ test/artifact_bucket_test.go | 22 ---- test/embed_test.go | 5 + test/entrypoint_test.go | 5 + test/helm_task_test.go | 5 + test/hermetic_taskrun_test.go | 6 ++ test/ignore_step_error_test.go | 6 ++ test/kaniko_task_test.go | 5 + test/pipelinefinally_test.go | 15 +++ test/pipelinerun_test.go | 10 +- test/status_test.go | 6 ++ test/taskrun_test.go | 10 ++ 15 files changed, 246 insertions(+), 24 deletions(-) diff --git a/docs/spire.md b/docs/spire.md index 5bc4ab2a2f7..b43ebdd344e 100644 --- a/docs/spire.md +++ b/docs/spire.md @@ -282,4 +282,4 @@ The signatures are being verified by the Tekton controller, the process of verif ## Further Details -To learn more about SPIRE TaskRun attestations, check out the [TEP](https://github.com/tektoncd/community/blob/main/teps/0089-nonfalsifiable-provenance-support.md). \ No newline at end of file +To learn more about SPIRE TaskRun attestations, check out the [TEP](https://github.com/tektoncd/community/blob/main/teps/0089-nonfalsifiable-provenance-support.md). diff --git a/pkg/apis/config/feature_flags.go b/pkg/apis/config/feature_flags.go index c294daa608b..7f348b11307 100644 --- a/pkg/apis/config/feature_flags.go +++ b/pkg/apis/config/feature_flags.go @@ -142,6 +142,9 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) { if err := setEmbeddedStatus(cfgMap, DefaultEmbeddedStatus, &tc.EmbeddedStatus); err != nil { return nil, err } + if err := setFeature(enableSpire, DefaultEnableSpire, &tc.EnableSpire); err != nil { + return nil, err + } // Given that they are alpha features, Tekton Bundles and Custom Tasks should be switched on if // enable-api-fields is "alpha". If enable-api-fields is not "alpha" then fall back to the value of diff --git a/pkg/pod/pod.go b/pkg/pod/pod.go index 28638aaebf0..859a9dec238 100644 --- a/pkg/pod/pod.go +++ b/pkg/pod/pod.go @@ -193,6 +193,7 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1beta1.TaskRun, taskSpec } readyImmediately := isPodReadyImmediately(*featureFlags, taskSpec.Sidecars) + // append credEntrypointArgs with entrypoint arg that contains if spire is enabled by configmap commonExtraEntrypointArgs = append(commonExtraEntrypointArgs, credEntrypointArgs...) diff --git a/pkg/pod/pod_test.go b/pkg/pod/pod_test.go index f079a4bbd40..5b11a7f93d6 100644 --- a/pkg/pod/pod_test.go +++ b/pkg/pod/pod_test.go @@ -2219,6 +2219,175 @@ func TestPodBuildwithSpireEnabled(t *testing.T) { } } +func TestPodBuildwithSpireEnabled(t *testing.T) { + placeToolsInit := corev1.Container{ + Name: "place-tools", + Image: images.EntrypointImage, + WorkingDir: "/", + Command: []string{"/ko-app/entrypoint", "cp", "/ko-app/entrypoint", "/tekton/bin/entrypoint"}, + VolumeMounts: []corev1.VolumeMount{binMount}, + } + + initContainers := []corev1.Container{placeToolsInit, tektonDirInit(images.EntrypointImage, []v1beta1.Step{{Name: "name"}})} + for i := range initContainers { + c := &initContainers[i] + c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{ + Name: "spiffe-workload-api", + MountPath: "/spiffe-workload-api", + }) + } + + for _, c := range []struct { + desc string + trs v1beta1.TaskRunSpec + trAnnotation map[string]string + ts v1beta1.TaskSpec + want *corev1.PodSpec + wantAnnotations map[string]string + }{{ + desc: "simple with debug breakpoint onFailure", + trs: v1beta1.TaskRunSpec{ + Debug: &v1beta1.TaskRunDebug{ + Breakpoint: []string{breakpointOnFailure}, + }, + }, + ts: v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{ + Name: "name", + Image: "image", + Command: []string{"cmd"}, // avoid entrypoint lookup. + }}, + }, + want: &corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + InitContainers: initContainers, + Containers: []corev1.Container{{ + Name: "step-name", + Image: "image", + Command: []string{"/tekton/bin/entrypoint"}, + Args: []string{ + "-wait_file", + "/tekton/downward/ready", + "-wait_file_content", + "-post_file", + "/tekton/run/0/out", + "-termination_path", + "/tekton/termination", + "-step_metadata_dir", + "/tekton/run/0/status", + "-enable_spire", + "-entrypoint", + "cmd", + "--", + }, + VolumeMounts: append([]corev1.VolumeMount{binROMount, runMount(0, false), downwardMount, { + Name: "tekton-creds-init-home-0", + MountPath: "/tekton/creds", + }, { + Name: "spiffe-workload-api", + MountPath: "/spiffe-workload-api", + }}, implicitVolumeMounts...), + TerminationMessagePath: "/tekton/termination", + }}, + Volumes: append(implicitVolumes, binVolume, runVolume(0), downwardVolume, corev1.Volume{ + Name: "tekton-creds-init-home-0", + VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{Medium: corev1.StorageMediumMemory}}, + }, corev1.Volume{ + Name: "spiffe-workload-api", + VolumeSource: corev1.VolumeSource{ + CSI: &corev1.CSIVolumeSource{ + Driver: "csi.spiffe.io", + }, + }, + }), + ActiveDeadlineSeconds: &defaultActiveDeadlineSeconds, + }, + }} { + t.Run(c.desc, func(t *testing.T) { + featureFlags := map[string]string{ + "enable-spire": "true", + } + names.TestingSeed() + store := config.NewStore(logtesting.TestLogger(t)) + store.OnConfigChanged( + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: config.GetFeatureFlagsConfigName(), Namespace: system.Namespace()}, + Data: featureFlags, + }, + ) + kubeclient := fakek8s.NewSimpleClientset( + &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}}, + &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "service-account", Namespace: "default"}, + Secrets: []corev1.ObjectReference{{ + Name: "multi-creds", + }}, + }, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multi-creds", + Namespace: "default", + Annotations: map[string]string{ + "tekton.dev/docker-0": "https://us.gcr.io", + "tekton.dev/docker-1": "https://docker.io", + "tekton.dev/git-0": "github.com", + "tekton.dev/git-1": "gitlab.com", + }}, + Type: "kubernetes.io/basic-auth", + Data: map[string][]byte{ + "username": []byte("foo"), + "password": []byte("BestEver"), + }, + }, + ) + var trAnnotations map[string]string + if c.trAnnotation == nil { + trAnnotations = map[string]string{ + ReleaseAnnotation: fakeVersion, + } + } else { + trAnnotations = c.trAnnotation + trAnnotations[ReleaseAnnotation] = fakeVersion + } + tr := &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "taskrun-name", + Namespace: "default", + Annotations: trAnnotations, + }, + Spec: c.trs, + } + + // No entrypoints should be looked up. + entrypointCache := fakeCache{} + builder := Builder{ + Images: images, + KubeClient: kubeclient, + EntrypointCache: entrypointCache, + } + + got, err := builder.Build(store.ToContext(context.Background()), tr, c.ts) + if err != nil { + t.Fatalf("builder.Build: %v", err) + } + + expectedName := kmeta.ChildName(tr.Name, "-pod") + if d := cmp.Diff(expectedName, got.Name); d != "" { + t.Errorf("Pod name does not match: %q", d) + } + + if d := cmp.Diff(c.want, &got.Spec, resourceQuantityCmp, volumeSort, volumeMountSort); d != "" { + t.Errorf("Diff %s", diff.PrintWantGot(d)) + } + + if c.wantAnnotations != nil { + if d := cmp.Diff(c.wantAnnotations, got.ObjectMeta.Annotations, cmpopts.IgnoreMapEntries(ignoreReleaseAnnotation)); d != "" { + t.Errorf("Annotation Diff(-want, +got):\n%s", d) + } + } + }) + } +} + func TestMakeLabels(t *testing.T) { taskRunName := "task-run-name" want := map[string]string{ diff --git a/test/artifact_bucket_test.go b/test/artifact_bucket_test.go index db75c74f7f2..98ceafd6219 100644 --- a/test/artifact_bucket_test.go +++ b/test/artifact_bucket_test.go @@ -33,13 +33,11 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" knativetest "knative.dev/pkg/test" "knative.dev/pkg/test/helpers" ) const ( - systemNamespace = "tekton-pipelines" bucketSecretName = "bucket-secret" bucketSecretKey = "bucket-secret-key" ) @@ -258,26 +256,6 @@ spec: } } -// updateConfigMap updates the config map for specified @name with values. We can't use the one from knativetest because -// it assumes that Data is already a non-nil map, and by default, it isn't! -func updateConfigMap(ctx context.Context, client kubernetes.Interface, name string, configName string, values map[string]string) error { - configMap, err := client.CoreV1().ConfigMaps(name).Get(ctx, configName, metav1.GetOptions{}) - if err != nil { - return err - } - - if configMap.Data == nil { - configMap.Data = make(map[string]string) - } - - for key, value := range values { - configMap.Data[key] = value - } - - _, err = client.CoreV1().ConfigMaps(name).Update(ctx, configMap, metav1.UpdateOptions{}) - return err -} - func getBucketSecret(t *testing.T, configFilePath, namespace string) *corev1.Secret { t.Helper() f, err := ioutil.ReadFile(configFilePath) diff --git a/test/embed_test.go b/test/embed_test.go index 0d473370d99..5273147faf9 100644 --- a/test/embed_test.go +++ b/test/embed_test.go @@ -27,6 +27,7 @@ import ( "github.com/tektoncd/pipeline/test/parse" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" knativetest "knative.dev/pkg/test" @@ -71,6 +72,10 @@ func embeddedResourceTest(t *testing.T, spireEnabled bool) { embedTaskName := helpers.ObjectNameForTest(t) embedTaskRunName := helpers.ObjectNameForTest(t) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } t.Logf("Creating Task and TaskRun in namespace %s", namespace) if _, err := c.TaskClient.Create(ctx, getEmbeddedTask(t, embedTaskName, namespace, []string{"/bin/sh", "-c", fmt.Sprintf("echo %s", taskOutput)}), metav1.CreateOptions{}); err != nil { diff --git a/test/entrypoint_test.go b/test/entrypoint_test.go index dbf84606fef..579fe886bb9 100644 --- a/test/entrypoint_test.go +++ b/test/entrypoint_test.go @@ -24,6 +24,7 @@ import ( "fmt" "testing" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/test/parse" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -67,6 +68,10 @@ func entryPointerTest(t *testing.T, spireEnabled bool) { defer tearDown(ctx, t, c, namespace) epTaskRunName := helpers.ObjectNameForTest(t) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } t.Logf("Creating TaskRun in namespace %s", namespace) if _, err := c.TaskRunClient.Create(ctx, parse.MustParseTaskRun(t, fmt.Sprintf(` diff --git a/test/helm_task_test.go b/test/helm_task_test.go index 6f46d19d3cd..51a78835f3a 100644 --- a/test/helm_task_test.go +++ b/test/helm_task_test.go @@ -81,6 +81,11 @@ func helmDeploytest(t *testing.T, spireEnabled bool) { knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + t.Logf("Creating Git PipelineResource %s", sourceResourceName) if _, err := c.PipelineResourceClient.Create(ctx, getGoHelloworldGitResource(t, sourceResourceName), metav1.CreateOptions{}); err != nil { t.Fatalf("Failed to create Pipeline Resource `%s`: %s", sourceResourceName, err) diff --git a/test/hermetic_taskrun_test.go b/test/hermetic_taskrun_test.go index 79727b48931..f5c5482cd87 100644 --- a/test/hermetic_taskrun_test.go +++ b/test/hermetic_taskrun_test.go @@ -26,6 +26,7 @@ import ( "github.com/tektoncd/pipeline/test/parse" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -61,6 +62,11 @@ func hermeticTest(t *testing.T, spireEnabled bool) { t.Parallel() defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + tests := []struct { desc string getTaskRun func(*testing.T, string, string, string) *v1beta1.TaskRun diff --git a/test/ignore_step_error_test.go b/test/ignore_step_error_test.go index b6522f0735e..4dbe0c22648 100644 --- a/test/ignore_step_error_test.go +++ b/test/ignore_step_error_test.go @@ -26,6 +26,7 @@ import ( "github.com/tektoncd/pipeline/test/parse" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" knativetest "knative.dev/pkg/test" @@ -57,6 +58,11 @@ func stepErrorTest(t *testing.T, spireEnabled bool) { knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + pipelineRun := parse.MustParsePipelineRun(t, fmt.Sprintf(` metadata: name: %s diff --git a/test/kaniko_task_test.go b/test/kaniko_task_test.go index 45e152c6d06..605e9f8d4f4 100644 --- a/test/kaniko_task_test.go +++ b/test/kaniko_task_test.go @@ -81,6 +81,11 @@ func kanikoTest(t *testing.T, spireEnabled bool) { t.Fatalf("Failed to create Pipeline Resource `%s`: %s", git.Name, err) } + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + image := getImageResource(t, repo) t.Logf("Creating Image PipelineResource %s", repo) if _, err := c.PipelineResourceClient.Create(ctx, image, metav1.CreateOptions{}); err != nil { diff --git a/test/pipelinefinally_test.go b/test/pipelinefinally_test.go index c7867660ec3..8e9b3005d22 100644 --- a/test/pipelinefinally_test.go +++ b/test/pipelinefinally_test.go @@ -471,6 +471,11 @@ func pipelineLevelFinallyOneFinalTaskFailedFailureWithOptions(t *testing.T, spir knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + task := getSuccessTask(t, namespace) if _, err := c.TaskClient.Create(ctx, task, metav1.CreateOptions{}); err != nil { t.Fatalf("Failed to create dag Task: %s", err) @@ -562,6 +567,11 @@ func pipelineLevelFinallyOneFinalTaskCancelledRunFinallyWithOptions(t *testing.T knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + task1 := getDelaySuccessTaskProducingResults(t, namespace) task1.Spec.Results = append(task1.Spec.Results, v1beta1.TaskResult{ Name: "result", @@ -706,6 +716,11 @@ func pipelineLevelFinallyOneFinalTaskStoppedRunFinallyWithOptions(t *testing.T, knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + task1 := getDelaySuccessTaskProducingResults(t, namespace) task1.Spec.Results = append(task1.Spec.Results, v1beta1.TaskResult{ Name: "result", diff --git a/test/pipelinerun_test.go b/test/pipelinerun_test.go index 2f180dad407..9cff8c75076 100644 --- a/test/pipelinerun_test.go +++ b/test/pipelinerun_test.go @@ -320,7 +320,6 @@ spec: i := i // capture range variable td := td // capture range variable t.Run(td.name, func(t *testing.T) { - t.Parallel() ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -337,6 +336,11 @@ spec: knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + t.Logf("Setting up test resources for %q test in namespace %s", td.name, namespace) resources, p := td.testSetup(ctx, t, c, namespace, i) @@ -602,6 +606,10 @@ func pipelineRunPendingTestWithOptions(t *testing.T, spireEnabled bool) { taskName := helpers.ObjectNameForTest(t) pipelineName := helpers.ObjectNameForTest(t) prName := helpers.ObjectNameForTest(t) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } t.Logf("Creating Task, Pipeline, and Pending PipelineRun %s in namespace %s", prName, namespace) diff --git a/test/status_test.go b/test/status_test.go index d53d2a40c33..8f6a733e2bd 100644 --- a/test/status_test.go +++ b/test/status_test.go @@ -24,6 +24,7 @@ import ( "fmt" "testing" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/test/parse" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -64,6 +65,11 @@ func taskRunPipelineRunStatus(t *testing.T, spireEnabled bool) { knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + t.Logf("Creating Task and TaskRun in namespace %s", namespace) task := parse.MustParseTask(t, fmt.Sprintf(` metadata: diff --git a/test/taskrun_test.go b/test/taskrun_test.go index 2cfcf1c100c..6df78077487 100644 --- a/test/taskrun_test.go +++ b/test/taskrun_test.go @@ -32,6 +32,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "github.com/tektoncd/pipeline/pkg/pod" corev1 "k8s.io/api/core/v1" @@ -70,6 +71,11 @@ func taskrunFailureTest(t *testing.T, spireEnabled bool) { taskRunName := helpers.ObjectNameForTest(t) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } + t.Logf("Creating Task and TaskRun in namespace %s", namespace) task := parse.MustParseTask(t, fmt.Sprintf(` metadata: @@ -186,6 +192,10 @@ func taskrunStatusTest(t *testing.T, spireEnabled bool) { defer tearDown(ctx, t, c, namespace) taskRunName := helpers.ObjectNameForTest(t) + if spireEnabled { + originalConfigMapData := enableSpireConfigMap(ctx, c, t) + defer resetConfigMap(ctx, t, c, systemNamespace, config.GetFeatureFlagsConfigName(), originalConfigMapData) + } fqImageName := getTestImage(busyboxImage)