Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SHIP-0036: Part 2: Introduce securityContext for build strategy spec #1266

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .ko.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
defaultBaseImage: registry.access.redhat.com/ubi9/ubi-minimal

baseImageOverrides:
github.com/shipwright-io/build/cmd/bundle: ghcr.io/shipwright-io/base-base:latest
github.com/shipwright-io/build/cmd/git: ghcr.io/shipwright-io/base-git:latest
github.com/shipwright-io/build/cmd/image-processing: ghcr.io/shipwright-io/base-image-processing:latest
github.com/shipwright-io/build/cmd/waiter: ghcr.io/shipwright-io/base-waiter:latest
6 changes: 6 additions & 0 deletions cmd/git/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type settings struct {
gitURLRewrite bool
resultFileErrorMessage string
resultFileErrorReason string
verbose bool
}

var flagValues settings
Expand Down Expand Up @@ -95,6 +96,7 @@ func init() {
// Mostly internal flag
pflag.BoolVar(&flagValues.skipValidation, "skip-validation", false, "skip pre-requisite validation")
pflag.BoolVar(&flagValues.gitURLRewrite, "git-url-rewrite", false, "set Git config to use url-insteadOf setting based on Git repository URL")
pflag.BoolVar(&flagValues.verbose, "verbose", false, "Verbose logging")
}

func main() {
Expand Down Expand Up @@ -209,8 +211,12 @@ func checkEnvironment(ctx context.Context) error {
return &ExitError{Code: 120, Message: err.Error(), Cause: err}
}

if flagValues.verbose {
log.Printf("Debug: %s %s\n", path, check.versionArg)
}
Comment on lines +214 to +216
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is really just that line, I would actually say to remove the verbose flag.

out, err := exec.CommandContext(ctx, path, check.versionArg).CombinedOutput()
if err != nil {
log.Printf("Error: %s: %s\n", check.toolName, strings.TrimRight(string(out), "\n"))
return err
}

Expand Down
48 changes: 48 additions & 0 deletions deploy/crds/shipwright.io_buildstrategies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,30 @@ spec:
- name
type: object
type: array
securityContext:
description: BuildStrategySecurityContext defines a UID and GID for
the build that is to be used for the build strategy steps as well
as for shipwright-managed steps such as the source retrieval, or
the image processing. The value can be overwritten on the steps
for the strategy steps. If omitted, then UID and GID from the Shipwright
configuration will be used for the shipwright-managed steps.
properties:
runAsGroup:
description: The GID to run the entrypoint of the container process.
Defaults to group specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
runAsUser:
description: The UID to run the entrypoint of the container process.
Defaults to user specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
required:
- runAsGroup
- runAsUser
type: object
volumes:
items:
description: BuildStrategyVolume is a volume that will be mounted
Expand Down Expand Up @@ -2874,6 +2898,30 @@ spec:
- name
type: object
type: array
securityContext:
description: BuildStrategySecurityContext defines a UID and GID for
the build that is to be used for the build strategy steps as well
as for shipwright-managed steps such as the source retrieval, or
the image processing. The value can be overwritten on the steps
for the strategy steps. If omitted, then UID and GID from the Shipwright
configuration will be used for the shipwright-managed steps.
properties:
runAsGroup:
description: The GID to run the entrypoint of the container process.
Defaults to group specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
runAsUser:
description: The UID to run the entrypoint of the container process.
Defaults to user specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
required:
- runAsGroup
- runAsUser
type: object
steps:
items:
description: BuildStep defines a partial step that needs to run
Expand Down
48 changes: 48 additions & 0 deletions deploy/crds/shipwright.io_clusterbuildstrategies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,30 @@ spec:
- name
type: object
type: array
securityContext:
description: BuildStrategySecurityContext defines a UID and GID for
the build that is to be used for the build strategy steps as well
as for shipwright-managed steps such as the source retrieval, or
the image processing. The value can be overwritten on the steps
for the strategy steps. If omitted, then UID and GID from the Shipwright
configuration will be used for the shipwright-managed steps.
properties:
runAsGroup:
description: The GID to run the entrypoint of the container process.
Defaults to group specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
runAsUser:
description: The UID to run the entrypoint of the container process.
Defaults to user specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
required:
- runAsGroup
- runAsUser
type: object
volumes:
items:
description: BuildStrategyVolume is a volume that will be mounted
Expand Down Expand Up @@ -2874,6 +2898,30 @@ spec:
- name
type: object
type: array
securityContext:
description: BuildStrategySecurityContext defines a UID and GID for
the build that is to be used for the build strategy steps as well
as for shipwright-managed steps such as the source retrieval, or
the image processing. The value can be overwritten on the steps
for the strategy steps. If omitted, then UID and GID from the Shipwright
configuration will be used for the shipwright-managed steps.
properties:
runAsGroup:
description: The GID to run the entrypoint of the container process.
Defaults to group specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
runAsUser:
description: The UID to run the entrypoint of the container process.
Defaults to user specified in image metadata if unspecified.
Can be overwritten by the security context on the step level.
format: int64
type: integer
required:
- runAsGroup
- runAsUser
type: object
steps:
items:
description: BuildStep defines a partial step that needs to run
Expand Down
18 changes: 18 additions & 0 deletions docs/buildstrategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ SPDX-License-Identifier: Apache-2.0
- [System parameters vs Strategy Parameters Comparison](#system-parameters-vs-strategy-parameters-comparison)
- [Securely referencing string parameters](#securely-referencing-string-parameters)
- [System results](#system-results)
- [Security Contexts](#security-contexts)
- [Steps Resource Definition](#steps-resource-definition)
- [Strategies with different resources](#strategies-with-different-resources)
- [How does Tekton Pipelines handle resources](#how-does-tekton-pipelines-handle-resources)
Expand Down Expand Up @@ -580,6 +581,23 @@ status:
reason: GitRemotePrivate
```

## Security Contexts

In a build strategy, it is recommended that you define a `securityContext` with a runAsUser and runAsGroup:

```yaml
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
```

This runAs configuration will be used for all shipwright-managed steps such as the step that retrieves the source code, and for the steps you define in the build strategy. This configuration ensures that all steps share the same runAs configuration which eliminates file permission problems.

Without a `securityContext` for the build strategy, shipwright-managed steps will run with the `runAsUser` and `runAsGroup` that is defined in the [configuration's container templates](configuration.md) that is potentially a different user than you use in your build strategy. This can result in issues when for example source code is downloaded as user A as defined by the Git container template, but your strategy accesses it as user B.

In build strategy steps you can define a step-specific `securityContext` that matches [Kubernetes' security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) where you can configure other security aspects such as capabilities or privileged containers.

## Steps Resource Definition

All strategies steps can include a definition of resources(_limits and requests_) for CPU, memory and disk. For strategies with more than one step, each step(_container_) could require more resources than others. Strategy admins are free to define the values that they consider the best fit for each step. Also, identical strategies with the same steps that are only different in their name and step resources can be installed on the cluster to allow users to create a build with smaller and larger resource requirements.
Expand Down
10 changes: 6 additions & 4 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ The following environment variables are available:
| `REMOTE_ARTIFACTS_CONTAINER_IMAGE` | Specify the container image used for the `.spec.sources` remote artifacts download, by default it uses `quay.io/quay/busybox:latest`. |
| `TERMINATION_LOG_PATH` | Path of the termination log. This is where controller application will write the reason of its termination. Default value is `/dev/termination-log`. |
| `GIT_ENABLE_REWRITE_RULE` | Enable Git wrapper to setup a URL `insteadOf` Git config rewrite rule for the respective source URL hostname. Default is `false`. |
| `GIT_CONTAINER_TEMPLATE` | JSON representation of a [Container] template that is used for steps that clone a Git repository. Default is `{"image":"ghcr.io/shipwright-io/build/git:latest", "command":["/ko-app/git"], "env": [{"name": "HOME","value": "/tekton/home"}], "securityContext":{"runAsUser":1000,"runAsGroup":1000}}`. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `GIT_CONTAINER_TEMPLATE` | JSON representation of a [Container] template that is used for steps that clone a Git repository. Default is `{"image": "ghcr.io/shipwright-io/build/git:latest", "command": ["/ko-app/git"], "env": [{"name": "HOME", "value": "/shared-home"}], "securityContext":{"allowPrivilegeEscalation": false, "capabilities": {"drop": ["ALL"]}, "runAsUser": 1000,"runAsGroup": 1000}}` [^1]. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `GIT_CONTAINER_IMAGE` | Custom container image for Git clone steps. If `GIT_CONTAINER_TEMPLATE` is also specifying an image, then the value for `GIT_CONTAINER_IMAGE` has precedence. |
| `BUNDLE_IMAGE_CONTAINER_TEMPLATE` | JSON representation of a [Container] template that is used for steps that pulls a bundle image to obtain the packaged source code. Default is `{"image": "ghcr.io/shipwright-io/build/bundle:latest", "command": ["/ko-app/bundle"], "env": [{"name": "HOME","value": "/tekton/home"}], "securityContext":{"runAsUser":1000,"runAsGroup":1000}}`. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `BUNDLE_IMAGE_CONTAINER_TEMPLATE` | JSON representation of a [Container] template that is used for steps that pulls a bundle image to obtain the packaged source code. Default is `{"image": "ghcr.io/shipwright-io/build/bundle:latest", "command": ["/ko-app/bundle"], "env": [{"name": "HOME","value": "/shared-home"}], "securityContext":{"allowPrivilegeEscalation": false, "capabilities": {"drop": ["ALL"]}, "runAsUser":1000,"runAsGroup":1000}}` [^1]. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `BUNDLE_IMAGE_CONTAINER_IMAGE` | Custom container image that pulls a bundle image to obtain the packaged source code. If `BUNDLE_IMAGE_CONTAINER_TEMPLATE` is also specifying an image, then the value for `BUNDLE_IMAGE_CONTAINER_IMAGE` has precedence. |
| `IMAGE_PROCESSING_CONTAINER_TEMPLATE` | JSON representation of a [Container](https://pkg.go.dev/k8s.io/api/core/v1#Container) template that is used for steps that processes the image. Default is `{"image": "ghcr.io/shipwright-io/build/image-processing:latest", "command": ["/ko-app/image-processing"], "env": [{"name": "HOME","value": "/tekton/home"}], "securityContext": {"runAsUser": 0, "capabilities": {"add": ["DAC_OVERRIDE"]}}}`. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `IMAGE_PROCESSING_CONTAINER_TEMPLATE` | JSON representation of a [Container](https://pkg.go.dev/k8s.io/api/core/v1#Container) template that is used for steps that processes the image. Default is `{"image": "ghcr.io/shipwright-io/build/image-processing:latest", "command": ["/ko-app/image-processing"], "env": [{"name": "HOME","value": "/shared-home"}], "securityContext": {"allowPrivilegeEscalation": false, "capabilities": {"add": ["DAC_OVERRIDE"], "drop": ["ALL"]}, "runAsUser": 0, "runAsgGroup": 0}}`. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `IMAGE_PROCESSING_CONTAINER_IMAGE` | Custom container image that is used for steps that processes the image. If `IMAGE_PROCESSING_CONTAINER_TEMPLATE` is also specifying an image, then the value for `IMAGE_PROCESSING_CONTAINER_IMAGE` has precedence. |
| `WAITER_IMAGE_CONTAINER_TEMPLATE` | JSON representation of a [Container] template that waits for local source code to be uploaded to it. Default is `{"image":"ghcr.io/shipwright-io/build/waiter:latest", "command": ["/ko-app/waiter"], "args": ["start"], "env": [{"name": "HOME","value": "/tekton/home"}], "securityContext":{"runAsUser":1000,"runAsGroup":1000}}`. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `WAITER_IMAGE_CONTAINER_TEMPLATE` | JSON representation of a [Container] template that waits for local source code to be uploaded to it. Default is `{"image":"ghcr.io/shipwright-io/build/waiter:latest", "command": ["/ko-app/waiter"], "args": ["start"], "env": [{"name": "HOME","value": "/shared-home"}], "securityContext":{"allowPrivilegeEscalation": false, "capabilities": {"drop": ["ALL"]}, "runAsUser":1000,"runAsGroup":1000}}`. The following properties are ignored as they are set by the controller: `args`, `name`. |
| `WAITER_IMAGE_CONTAINER_IMAGE` | Custom container image that waits for local source code to be uploaded to it. If `WAITER_IMAGE_CONTAINER_TEMPLATE` is also specifying an image, then the value for `WAITER_IMAGE_CONTAINER_IMAGE` has precedence. |
| `BUILD_CONTROLLER_LEADER_ELECTION_NAMESPACE` | Set the namespace to be used to store the `shipwright-build-controller` lock, by default it is in the same namespace as the controller itself. |
| `BUILD_CONTROLLER_LEASE_DURATION` | Override the `LeaseDuration`, which is the duration that non-leader candidates will wait to force acquire leadership. |
Expand All @@ -37,6 +37,8 @@ The following environment variables are available:
| `KUBE_API_BURST` | Burst to use for the Kubernetes API client. See [Config.Burst]. A value of 0 or lower will use the default from client-go, which currently is 10. Default is 0. |
| `KUBE_API_QPS` | QPS to use for the Kubernetes API client. See [Config.QPS]. A value of 0 or lower will use the default from client-go, which currently is 5. Default is 0. |

[^1]: The `runAsUser` and `runAsGroup` are dynamically overwritten depending on the build strategy that is used. See [Security Contexts](buildstrategies.md#security-contexts) for more information.

## Role-based Access Control

The release deployment YAML file includes two cluster-wide roles for using Shipwright Build objects.
Expand Down
25 changes: 22 additions & 3 deletions pkg/apis/build/v1alpha1/buildstrategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ const (

// BuildStrategySpec defines the desired state of BuildStrategy
type BuildStrategySpec struct {
BuildSteps []BuildStep `json:"buildSteps,omitempty"`
Parameters []Parameter `json:"parameters,omitempty"`
Volumes []BuildStrategyVolume `json:"volumes,omitempty"`
BuildSteps []BuildStep `json:"buildSteps,omitempty"`
Parameters []Parameter `json:"parameters,omitempty"`
SecurityContext *BuildStrategySecurityContext `json:"securityContext,omitempty"`
Volumes []BuildStrategyVolume `json:"volumes,omitempty"`
}

// ParameterType indicates the type of a parameter
Expand Down Expand Up @@ -90,6 +91,23 @@ type BuildStep struct {
corev1.Container `json:",inline"`
}

// BuildStrategySecurityContext defines a UID and GID for the build that is to be used for the build strategy steps as
// well as for shipwright-managed steps such as the source retrieval, or the image processing.
// The value can be overwritten on the steps for the strategy steps.
// If omitted, then UID and GID from the Shipwright configuration will be used for the shipwright-managed steps.
type BuildStrategySecurityContext struct {

// The UID to run the entrypoint of the container process.
// Defaults to user specified in image metadata if unspecified.
// Can be overwritten by the security context on the step level.
RunAsUser int64 `json:"runAsUser"`

// The GID to run the entrypoint of the container process.
// Defaults to group specified in image metadata if unspecified.
// Can be overwritten by the security context on the step level.
RunAsGroup int64 `json:"runAsGroup"`
}

// BuildStrategyStatus defines the observed state of BuildStrategy
type BuildStrategyStatus struct {
}
Expand Down Expand Up @@ -119,5 +137,6 @@ type BuilderStrategy interface {
GetResourceLabels() map[string]string
GetBuildSteps() []BuildStep
GetParameters() []Parameter
GetSecurityContext() *BuildStrategySecurityContext
GetVolumes() []BuildStrategyVolume
}
5 changes: 5 additions & 0 deletions pkg/apis/build/v1alpha1/buildstrategy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ func (s BuildStrategy) GetParameters() []Parameter {
return s.Spec.Parameters
}

// GetSecurityContext returns the security context defined by the build strategy
func (s BuildStrategy) GetSecurityContext() *BuildStrategySecurityContext {
return s.Spec.SecurityContext
}

// GetVolumes returns the volumes defined by the build strategy
func (s BuildStrategy) GetVolumes() []BuildStrategyVolume {
return s.Spec.Volumes
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/build/v1alpha1/clusterbuildstrategy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ func (s ClusterBuildStrategy) GetParameters() []Parameter {
return s.Spec.Parameters
}

// GetSecurityContext returns the security context defined by the build strategy
func (s ClusterBuildStrategy) GetSecurityContext() *BuildStrategySecurityContext {
return s.Spec.SecurityContext
}

// GetVolumes returns the volumes defined by the build strategy
func (s ClusterBuildStrategy) GetVolumes() []BuildStrategyVolume {
return s.Spec.Volumes
Expand Down