From 64f593de4df9e5195e90f65190567bba60f12636 Mon Sep 17 00:00:00 2001 From: Yongxuan Zhang Date: Sun, 5 Nov 2023 23:34:07 +0000 Subject: [PATCH] [TEP-0142] Add SecurityContext This commit adds SecurityContext to StepAction. Signed-off-by: Yongxuan Zhang yongxuanzhang@google.com --- docs/pipeline-api.md | 34 +++++++++++++++++ docs/stepactions.md | 33 +++++++++++++--- .../pipeline/v1alpha1/openapi_generated.go | 8 +++- .../pipeline/v1alpha1/stepaction_types.go | 6 +++ pkg/apis/pipeline/v1alpha1/swagger.json | 4 ++ .../v1alpha1/zz_generated.deepcopy.go | 5 +++ pkg/reconciler/taskrun/resources/taskspec.go | 1 + .../taskrun/resources/taskspec_test.go | 38 +++++++++++++++++++ pkg/reconciler/taskrun/taskrun_test.go | 12 ++++-- 9 files changed, 130 insertions(+), 11 deletions(-) diff --git a/docs/pipeline-api.md b/docs/pipeline-api.md index d2f6a4d93b7..f8bed1decf7 100644 --- a/docs/pipeline-api.md +++ b/docs/pipeline-api.md @@ -6598,6 +6598,23 @@ Params must be supplied as inputs in Steps unless they declare a defaultvalue.Results are values that this StepAction can output

+ + +securityContext
+ + +Kubernetes core/v1.SecurityContext + + + + +(Optional) +

SecurityContext defines the security options the Step should be run with. +If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. +More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +The value set in StepAction will take precedence over the value from Task.

+ + @@ -7457,6 +7474,23 @@ Params must be supplied as inputs in Steps unless they declare a defaultvalue.Results are values that this StepAction can output

+ + +securityContext
+ + +Kubernetes core/v1.SecurityContext + + + + +(Optional) +

SecurityContext defines the security options the Step should be run with. +If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. +More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +The value set in StepAction will take precedence over the value from Task.

+ +

VerificationPolicySpec diff --git a/docs/stepactions.md b/docs/stepactions.md index c1acec55d5f..0169b4e6953 100644 --- a/docs/stepactions.md +++ b/docs/stepactions.md @@ -17,7 +17,7 @@ A `StepAction` is the reusable and scriptable unit of work that is performed by A `Step` is not reusable, the work it performs is reusable and referenceable. `Steps` are in-lined in the `Task` definition and either perform work directly or perform a `StepAction`. A `StepAction` cannot be run stand-alone (unlike a `TaskRun` or a `PipelineRun`). It has to be referenced by a `Step`. Another way to ehink about this is that a `Step` is not composed of `StepActions` (unlike a `Task` being composed of `Steps` and `Sidecars`). Instead, a `Step` is an actionable component, meaning that it has the ability to refer to a `StepAction`. The author of the `StepAction` must be able to compose a `Step` using a `StepAction` and provide all the necessary context (or orchestration) to it. - + ## Configuring a `StepAction` A `StepAction` definition supports the following fields: @@ -29,7 +29,7 @@ A `StepAction` definition supports the following fields: - [`metadata`][kubernetes-overview] - Specifies metadata that uniquely identifies the `StepAction` resource object. For example, a `name`. - [`spec`][kubernetes-overview] - Specifies the configuration information for this `StepAction` resource object. - - `image` - Specifies the image to use for the `Step`. + - `image` - Specifies the image to use for the `Step`. - The container image must abide by the [container contract](./container-contract.md). - Optional - `command` @@ -40,6 +40,7 @@ A `StepAction` definition supports the following fields: - `env` - [`params`](#declaring-params) - [`results`](#declaring-results) + - [`securityContext`](#declaring-securitycontext) The non-functional example below demonstrates the use of most of the above-mentioned fields: @@ -52,15 +53,15 @@ spec: env: - name: HOME value: /home - image: ubuntu + image: ubuntu command: ["ls"] args: ["-lh"] ``` ### Declaring Parameters -Like with `Tasks`, a `StepAction` must declare all the parameters that it used. The same rules for `Parameter` [name](./tasks.md/#parameter-name), [type](./tasks.md/#parameter-type) (including [object](./tasks.md/#object-type), [array](./tasks.md/#array-type) and [string](./tasks.md/#string-type)) apply as when declaring them in `Tasks`. A `StepAction` can also provide [default value](./tasks.md/#default-value) to a `Parameter`. - +Like with `Tasks`, a `StepAction` must declare all the parameters that it used. The same rules for `Parameter` [name](./tasks.md/#parameter-name), [type](./tasks.md/#parameter-type) (including [object](./tasks.md/#object-type), [array](./tasks.md/#array-type) and [string](./tasks.md/#string-type)) apply as when declaring them in `Tasks`. A `StepAction` can also provide [default value](./tasks.md/#default-value) to a `Parameter`. + `Parameters` are passed to the `StepAction` from its corresponding `Step` referencing it. ```yaml @@ -93,7 +94,7 @@ spec: ### Declaring Results -A `StepAction` also declares the results that it will emit. +A `StepAction` also declares the results that it will emit. ```yaml apiVersion: tekton.dev/v1alpha1 @@ -113,6 +114,26 @@ spec: date | tee $(results.current-date-human-readable.path) ``` +### Declaring SecurityContext + +You can declare `securityContext` in a `StepAction`: + +```yaml +apiVersion: tekton.dev/v1alpha1 +kind: StepAction +metadata: + name: example-stepaction-name +spec: + image: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:latest + securityContext: + runAsUser: 0 + script: | + # clone the repo + ... +``` + +Note that the `securityContext` from `StepAction` will overwrite the `securityContext` from [`TaskRun`](./taskruns.md/#example-of-running-step-containers-as-a-non-root-user). + ## Referencing a StepAction `StepActions` can be referenced from the `Step` using the `ref` field, as follows: diff --git a/pkg/apis/pipeline/v1alpha1/openapi_generated.go b/pkg/apis/pipeline/v1alpha1/openapi_generated.go index 7638264c094..48b42c1663f 100644 --- a/pkg/apis/pipeline/v1alpha1/openapi_generated.go +++ b/pkg/apis/pipeline/v1alpha1/openapi_generated.go @@ -921,11 +921,17 @@ func schema_pkg_apis_pipeline_v1alpha1_StepActionSpec(ref common.ReferenceCallba }, }, }, + "securityContext": { + SchemaProps: spec.SchemaProps{ + Description: "SecurityContext defines the security options the Step should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ The value set in StepAction will take precedence over the value from Task.", + Ref: ref("k8s.io/api/core/v1.SecurityContext"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.ParamSpec", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1.StepActionResult", "k8s.io/api/core/v1.EnvVar"}, + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.ParamSpec", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1.StepActionResult", "k8s.io/api/core/v1.EnvVar", "k8s.io/api/core/v1.SecurityContext"}, } } diff --git a/pkg/apis/pipeline/v1alpha1/stepaction_types.go b/pkg/apis/pipeline/v1alpha1/stepaction_types.go index ce8d0934b6d..4e9efb77714 100644 --- a/pkg/apis/pipeline/v1alpha1/stepaction_types.go +++ b/pkg/apis/pipeline/v1alpha1/stepaction_types.go @@ -121,6 +121,12 @@ type StepActionSpec struct { // +optional // +listType=atomic Results []StepActionResult `json:"results,omitempty"` + // SecurityContext defines the security options the Step should be run with. + // If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + // The value set in StepAction will take precedence over the value from Task. + // +optional + SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty" protobuf:"bytes,15,opt,name=securityContext"` } // StepActionObject is implemented by StepAction diff --git a/pkg/apis/pipeline/v1alpha1/swagger.json b/pkg/apis/pipeline/v1alpha1/swagger.json index 14d777f80ea..aa6a859ecdc 100644 --- a/pkg/apis/pipeline/v1alpha1/swagger.json +++ b/pkg/apis/pipeline/v1alpha1/swagger.json @@ -472,6 +472,10 @@ "script": { "description": "Script is the contents of an executable file to execute.\n\nIf Script is not empty, the Step cannot have an Command and the Args will be passed to the Script.", "type": "string" + }, + "securityContext": { + "description": "SecurityContext defines the security options the Step should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ The value set in StepAction will take precedence over the value from Task.", + "$ref": "#/definitions/v1.SecurityContext" } } }, diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 7ee5bef9874..592f5961a91 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -335,6 +335,11 @@ func (in *StepActionSpec) DeepCopyInto(out *StepActionSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(v1.SecurityContext) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/reconciler/taskrun/resources/taskspec.go b/pkg/reconciler/taskrun/resources/taskspec.go index 4cc85145bb9..65d87dba3d5 100644 --- a/pkg/reconciler/taskrun/resources/taskspec.go +++ b/pkg/reconciler/taskrun/resources/taskspec.go @@ -112,6 +112,7 @@ func GetStepActionsData(ctx context.Context, taskSpec v1.TaskSpec, tr *v1.TaskRu } stepActionSpec := stepAction.StepActionSpec() s.Image = stepActionSpec.Image + s.SecurityContext = stepActionSpec.SecurityContext if len(stepActionSpec.Command) > 0 { s.Command = stepActionSpec.Command } diff --git a/pkg/reconciler/taskrun/resources/taskspec_test.go b/pkg/reconciler/taskrun/resources/taskspec_test.go index 37c174bcb35..6f1993a2032 100644 --- a/pkg/reconciler/taskrun/resources/taskspec_test.go +++ b/pkg/reconciler/taskrun/resources/taskspec_test.go @@ -301,6 +301,8 @@ func TestGetTaskData_VerificationResult(t *testing.T) { } func TestGetStepActionsData(t *testing.T) { + taskRunUser := int64(1001) + stepActionUser := int64(1000) tests := []struct { name string tr *v1.TaskRun @@ -454,6 +456,42 @@ func TestGetStepActionsData(t *testing.T) { Image: "foo", Command: []string{"ls"}, }}, + }, { + name: "step-action-with-security-context-overwritten", + tr: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Ref: &v1.Ref{ + Name: "stepAction", + }, + SecurityContext: &corev1.SecurityContext{RunAsUser: &taskRunUser}, + }}, + }, + }, + }, + stepAction: &v1alpha1.StepAction{ + ObjectMeta: metav1.ObjectMeta{ + Name: "stepAction", + Namespace: "default", + }, + Spec: v1alpha1.StepActionSpec{ + Image: "myimage", + Command: []string{"ls"}, + Args: []string{"-lh"}, + SecurityContext: &corev1.SecurityContext{RunAsUser: &stepActionUser}, + }, + }, + want: []v1.Step{{ + Image: "myimage", + Command: []string{"ls"}, + Args: []string{"-lh"}, + SecurityContext: &corev1.SecurityContext{RunAsUser: &stepActionUser}, + }}, }} for _, tt := range tests { ctx := context.Background() diff --git a/pkg/reconciler/taskrun/taskrun_test.go b/pkg/reconciler/taskrun/taskrun_test.go index b2813dd5a82..e00739ae282 100644 --- a/pkg/reconciler/taskrun/taskrun_test.go +++ b/pkg/reconciler/taskrun/taskrun_test.go @@ -2760,6 +2760,8 @@ metadata: spec: image: myImage command: ["ls"] + securityContext: + privileged: true `) stepAction2 := parse.MustParseV1alpha1StepAction(t, ` metadata: @@ -2790,11 +2792,13 @@ spec: } getTaskRun, _ := testAssets.Clients.Pipeline.TektonV1().TaskRuns(taskRun.Namespace).Get(testAssets.Ctx, taskRun.Name, metav1.GetOptions{}) got := getTaskRun.Status.TaskSpec.Steps + securityContextPrivileged := true want := []v1.Step{{ - Image: "myImage", - Command: []string{"ls"}, - Name: "step1", - WorkingDir: "/foo", + Image: "myImage", + Command: []string{"ls"}, + Name: "step1", + WorkingDir: "/foo", + SecurityContext: &corev1.SecurityContext{Privileged: &securityContextPrivileged}, }, { Image: "myImage", Script: "echo hi",