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",