From 8af9ecdb0ac0cbbe88a373a0458a4d2e4126736c Mon Sep 17 00:00:00 2001 From: Hasan Awad Date: Tue, 13 May 2025 14:47:32 +0300 Subject: [PATCH] Add ReadOnlyRootFilesystem securityContext to build steps Set the root filesystem to read-only for all build and buildstrategy containers as a security best practice. To support this, steps that require write access now explicitly mount `emptyDir` volumes for paths like `/tmp` `/home`. A new `AppendWriteableVolumes` function centralizes the setup for volume mounting , using idempotent helpers (`ensureVolume`, `ensureVolumeMount`) to prevent duplicate entries. The writeable home directory for the steps can be configured using `WRITABLE_HOME_DIR`. Default is value is `/writable-home` Signed-off-by: Hasan Awad --- docs/configuration.md | 3 +- pkg/config/config.go | 69 +++++++++++--- pkg/config/config_test.go | 18 ++-- .../buildrun/resources/image_processing.go | 18 +++- .../buildrun/resources/sources/bundle.go | 1 + .../buildrun/resources/sources/git.go | 2 +- .../buildrun/resources/sources/git_test.go | 8 +- .../buildrun/resources/sources/local_copy.go | 1 + .../buildrun/resources/sources/utils.go | 94 +++++++++++++++++++ .../buildrun/resources/taskrun_test.go | 2 +- ...gy_buildah_shipwright_managed_push_cr.yaml | 29 +++++- ...tegy_buildah_strategy_managed_push_cr.yaml | 19 ++++ .../buildkit/buildstrategy_buildkit_cr.yaml | 23 ++++- ...buildstrategy_buildpacks-v3-heroku_cr.yaml | 22 ++++- ...gy_buildpacks-v3-heroku_namespaced_cr.yaml | 22 ++++- .../buildstrategy_buildpacks-v3_cr.yaml | 24 ++++- ...dstrategy_buildpacks-v3_namespaced_cr.yaml | 24 ++++- ...dstrategy_multiarch_native_buildah_cr.yaml | 53 +++++++++++ 18 files changed, 387 insertions(+), 45 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 1abecc1dea..633df74a1d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -22,7 +22,7 @@ The following environment variables are available: | `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_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"},{"name": "BUNDLE_SHOW_LISTING","value": "false"}], "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_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": "/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_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"}, {"name": "TRIVY_CACHE_DIR", "value": "/trivy-cache-data/trivy-cache"}], "securityContext": {"allowPrivilegeEscalation": false, "capabilities": {"add": ["DAC_OVERRIDE"], "drop": ["ALL"]}, "runAsUser": 0, "runAsGroup": 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_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_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. | @@ -37,6 +37,7 @@ 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. | | `VULNERABILITY_COUNT_LIMIT` | holds vulnerability count limit if vulnerability scan is enabled for the output image. If it is defined as 10, then it will output only 10 vulnerabilities sorted by severity in the buildrun status.Output. Default is 50. | +| `WRITABLE_HOME_DIR` | Specifies the mount path for writable home directories in build containers. Each container gets its own isolated emptyDir volume mounted at this path, enabling write operations when `readOnlyRootFilesystem: true` is used. Default is `/writable-home`. | [^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. diff --git a/pkg/config/config.go b/pkg/config/config.go index 72d653358c..81b23f47b7 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -79,6 +79,17 @@ const ( // environment variable to hold vulnerability count limit VulnerabilityCountLimitEnvVar = "VULNERABILITY_COUNT_LIMIT" + + // Trivy related environment variables + trivyCacheDirEnvVar = "TRIVY_CACHE_DIR" + // Default paths for Trivy + defaultTrivyCacheDir = "/trivy-cache-data/trivy-cache" + + // Default writable home directory path inside containers + // Note: Each container gets its own isolated emptyDir volume mounted at this path + // The actual volume names are unique per container (e.g., shp-writable-home-step-name) + defaultWritableHomeDir = "/writable-home" + writableHomeDirEnvVar = "WRITABLE_HOME_DIR" ) var ( @@ -107,6 +118,14 @@ type Config struct { KubeAPIOptions KubeAPIOptions GitRewriteRule bool VulnerabilityCountLimit int + ContainersWritableDir WritableDirsConfig +} + +type WritableDirsConfig struct { + TrivyCacheDir string + // WritableHomeDir is the path where each container's writable home directory is mounted + // Each container gets its own isolated emptyDir volume at this mount path + WritableHomeDir string } // PrometheusConfig contains the specific configuration for the @@ -163,22 +182,28 @@ func NewDefaultConfig() *Config { TerminationLogPath: terminationLogPathDefault, GitRewriteRule: false, VulnerabilityCountLimit: 50, - + ContainersWritableDir: WritableDirsConfig{ + TrivyCacheDir: defaultTrivyCacheDir, + WritableHomeDir: defaultWritableHomeDir, + }, GitContainerTemplate: Step{ Image: gitDefaultImage, Command: []string{ "/ko-app/git", }, Env: []corev1.EnvVar{ - // This directory is created in the base image as writable for everybody { Name: "HOME", - Value: "/shared-home", + Value: defaultWritableHomeDir, }, { Name: "GIT_SHOW_LISTING", Value: "false", }, + { + Name: "TMPDIR", + Value: "/tmp", + }, }, SecurityContext: &corev1.SecurityContext{ AllowPrivilegeEscalation: ptr.To(false), @@ -187,8 +212,9 @@ func NewDefaultConfig() *Config { "ALL", }, }, - RunAsUser: nonRoot, - RunAsGroup: nonRoot, + RunAsUser: nonRoot, + RunAsGroup: nonRoot, + ReadOnlyRootFilesystem: ptr.To(true), }, }, @@ -197,11 +223,10 @@ func NewDefaultConfig() *Config { Command: []string{ "/ko-app/bundle", }, - // This directory is created in the base image as writable for everybody Env: []corev1.EnvVar{ { Name: "HOME", - Value: "/shared-home", + Value: defaultWritableHomeDir, }, { Name: "BUNDLE_SHOW_LISTING", @@ -215,8 +240,9 @@ func NewDefaultConfig() *Config { "ALL", }, }, - RunAsUser: nonRoot, - RunAsGroup: nonRoot, + RunAsUser: nonRoot, + RunAsGroup: nonRoot, + ReadOnlyRootFilesystem: ptr.To(true), }, }, @@ -225,11 +251,10 @@ func NewDefaultConfig() *Config { Command: []string{ "/ko-app/image-processing", }, - // This directory is created in the base image as writable for everybody Env: []corev1.EnvVar{ { Name: "HOME", - Value: "/shared-home", + Value: defaultWritableHomeDir, }, }, // The image processing step runs after the build strategy steps where an arbitrary @@ -241,6 +266,7 @@ func NewDefaultConfig() *Config { AllowPrivilegeEscalation: ptr.To(false), RunAsUser: root, RunAsGroup: root, + ReadOnlyRootFilesystem: ptr.To(true), Capabilities: &corev1.Capabilities{ Add: []corev1.Capability{ "DAC_OVERRIDE", @@ -260,11 +286,10 @@ func NewDefaultConfig() *Config { Args: []string{ "start", }, - // This directory is created in the base image as writable for everybody Env: []corev1.EnvVar{ { Name: "HOME", - Value: "/shared-home", + Value: defaultWritableHomeDir, }, }, SecurityContext: &corev1.SecurityContext{ @@ -274,8 +299,9 @@ func NewDefaultConfig() *Config { "ALL", }, }, - RunAsUser: nonRoot, - RunAsGroup: nonRoot, + RunAsUser: nonRoot, + RunAsGroup: nonRoot, + ReadOnlyRootFilesystem: ptr.To(true), }, }, @@ -455,6 +481,11 @@ func (c *Config) SetConfigFromEnv() error { c.TerminationLogPath = terminationLogPath } + // Update writable directory paths if environment variables are set + if err := updateWritableDirOption(&c.ContainersWritableDir.WritableHomeDir, writableHomeDirEnvVar); err != nil { + return err + } + return nil } @@ -509,3 +540,11 @@ func updateIntOption(i *int, envVarName string) error { return nil } + +// updateWritableDirOption updates the writable directory paths if the environment variable is set +func updateWritableDirOption(path *string, envVarName string) error { + if value := os.Getenv(envVarName); value != "" { + *path = value + } + return nil +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 569cc92dc7..3bff1fe101 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -132,8 +132,12 @@ var _ = Describe("Config", func() { "/ko-app/git", }, Env: []corev1.EnvVar{ - {Name: "HOME", Value: "/shared-home"}, + {Name: "HOME", Value: "/writable-home"}, {Name: "GIT_SHOW_LISTING", Value: "false"}, + { + Name: "TMPDIR", + Value: "/tmp", + }, }, SecurityContext: &corev1.SecurityContext{ AllowPrivilegeEscalation: ptr.To(false), @@ -142,8 +146,9 @@ var _ = Describe("Config", func() { "ALL", }, }, - RunAsUser: nonRoot, - RunAsGroup: nonRoot, + RunAsUser: nonRoot, + RunAsGroup: nonRoot, + ReadOnlyRootFilesystem: ptr.To(true), }, })) }) @@ -235,7 +240,7 @@ var _ = Describe("Config", func() { Image: "myregistry/custom/image", Command: []string{"/ko-app/waiter"}, Args: []string{"start"}, - Env: []corev1.EnvVar{{Name: "HOME", Value: "/shared-home"}}, + Env: []corev1.EnvVar{{Name: "HOME", Value: "/writable-home"}}, SecurityContext: &corev1.SecurityContext{ AllowPrivilegeEscalation: ptr.To(false), Capabilities: &corev1.Capabilities{ @@ -243,8 +248,9 @@ var _ = Describe("Config", func() { "ALL", }, }, - RunAsUser: nonRoot, - RunAsGroup: nonRoot, + RunAsUser: nonRoot, + RunAsGroup: nonRoot, + ReadOnlyRootFilesystem: ptr.To(true), }, })) }) diff --git a/pkg/reconciler/buildrun/resources/image_processing.go b/pkg/reconciler/buildrun/resources/image_processing.go index 0e3fda8e2c..e36481be56 100644 --- a/pkg/reconciler/buildrun/resources/image_processing.go +++ b/pkg/reconciler/buildrun/resources/image_processing.go @@ -174,7 +174,6 @@ func SetupImageProcessing(taskRun *pipelineapi.TaskRun, cfg *config.Config, crea SecurityContext: cfg.ImageProcessingContainerTemplate.SecurityContext, WorkingDir: cfg.ImageProcessingContainerTemplate.WorkingDir, } - if volumeAdded { imageProcessingStep.VolumeMounts = append(imageProcessingStep.VolumeMounts, core.VolumeMount{ Name: prefixedOutputDirectory, @@ -201,6 +200,23 @@ func SetupImageProcessing(taskRun *pipelineapi.TaskRun, cfg *config.Config, crea ) } + sources.AppendWriteableVolumes(taskRun.Spec.TaskSpec, &imageProcessingStep, cfg.ContainersWritableDir.WritableHomeDir) + + taskRun.Spec.TaskSpec.Volumes = append(taskRun.Spec.TaskSpec.Volumes, core.Volume{ + Name: "trivy-cache-data", + VolumeSource: core.VolumeSource{ + EmptyDir: &core.EmptyDirVolumeSource{}, + }, + }) + imageProcessingStep.VolumeMounts = append(imageProcessingStep.VolumeMounts, core.VolumeMount{ + Name: "trivy-cache-data", + MountPath: cfg.ContainersWritableDir.TrivyCacheDir, + }) + + imageProcessingStep.Env = append(imageProcessingStep.Env, core.EnvVar{ + Name: "TRIVY_CACHE_DIR", + Value: cfg.ContainersWritableDir.TrivyCacheDir, + }) // append the mutate step taskRun.Spec.TaskSpec.Steps = append(taskRun.Spec.TaskSpec.Steps, imageProcessingStep) } diff --git a/pkg/reconciler/buildrun/resources/sources/bundle.go b/pkg/reconciler/buildrun/resources/sources/bundle.go index ec39f1ab69..be7d009b52 100644 --- a/pkg/reconciler/buildrun/resources/sources/bundle.go +++ b/pkg/reconciler/buildrun/resources/sources/bundle.go @@ -67,6 +67,7 @@ func AppendBundleStep(cfg *config.Config, taskSpec *pipelineapi.TaskSpec, oci *b bundleStep.Args = append(bundleStep.Args, "--prune") } + AppendWriteableVolumes(taskSpec, &bundleStep, cfg.ContainersWritableDir.WritableHomeDir) taskSpec.Steps = append(taskSpec.Steps, bundleStep) } diff --git a/pkg/reconciler/buildrun/resources/sources/git.go b/pkg/reconciler/buildrun/resources/sources/git.go index af10d5b258..e922b8465e 100644 --- a/pkg/reconciler/buildrun/resources/sources/git.go +++ b/pkg/reconciler/buildrun/resources/sources/git.go @@ -114,7 +114,7 @@ func AppendGitStep( secretMountPath, ) } - + AppendWriteableVolumes(taskSpec, &gitStep, cfg.ContainersWritableDir.WritableHomeDir) // append the git step taskSpec.Steps = append(taskSpec.Steps, gitStep) } diff --git a/pkg/reconciler/buildrun/resources/sources/git_test.go b/pkg/reconciler/buildrun/resources/sources/git_test.go index 46c4bc440e..d46446b749 100644 --- a/pkg/reconciler/buildrun/resources/sources/git_test.go +++ b/pkg/reconciler/buildrun/resources/sources/git_test.go @@ -79,7 +79,7 @@ var _ = Describe("Git", func() { }) It("adds a volume for the secret", func() { - Expect(len(taskSpec.Volumes)).To(Equal(1)) + Expect(len(taskSpec.Volumes)).To(Equal(3)) Expect(taskSpec.Volumes[0].Name).To(Equal("shp-a-secret")) Expect(taskSpec.Volumes[0].VolumeSource.Secret).NotTo(BeNil()) Expect(taskSpec.Volumes[0].VolumeSource.Secret.SecretName).To(Equal("a.secret")) @@ -100,7 +100,7 @@ var _ = Describe("Git", func() { "--result-file-source-timestamp", "$(results.shp-source-default-source-timestamp.path)", "--secret-path", "/workspace/shp-source-secret", })) - Expect(len(taskSpec.Steps[0].VolumeMounts)).To(Equal(1)) + Expect(len(taskSpec.Steps[0].VolumeMounts)).To(Equal(3)) Expect(taskSpec.Steps[0].VolumeMounts[0].Name).To(Equal("shp-a-secret")) Expect(taskSpec.Steps[0].VolumeMounts[0].MountPath).To(Equal("/workspace/shp-source-secret")) Expect(taskSpec.Steps[0].VolumeMounts[0].ReadOnly).To(BeTrue()) @@ -188,7 +188,7 @@ var _ = Describe("Git", func() { Revision: ptr.To(revision), CloneSecret: ptr.To("another.secret"), }, "default") - + Expect(len(taskSpec.Steps)).To(Equal(1)) Expect(taskSpec.Steps[0].Args).To(ContainElements( "--url", "https://github.com/shipwright-io/another-repo", @@ -200,4 +200,4 @@ var _ = Describe("Git", func() { Expect(taskSpec.Steps[0].VolumeMounts).To(ContainElement(HaveField("Name", "shp-another-secret"))) }) }) -}) \ No newline at end of file +}) diff --git a/pkg/reconciler/buildrun/resources/sources/local_copy.go b/pkg/reconciler/buildrun/resources/sources/local_copy.go index 17670fa220..89bb7cfa5d 100644 --- a/pkg/reconciler/buildrun/resources/sources/local_copy.go +++ b/pkg/reconciler/buildrun/resources/sources/local_copy.go @@ -32,6 +32,7 @@ func AppendLocalCopyStep(cfg *config.Config, taskSpec *pipelineapi.TaskSpec, tim WorkingDir: cfg.WaiterContainerTemplate.WorkingDir, } + AppendWriteableVolumes(taskSpec, &step, cfg.ContainersWritableDir.WritableHomeDir) if timeout != nil { step.Args = append(step.Args, fmt.Sprintf("--timeout=%s", timeout.Duration.String())) } diff --git a/pkg/reconciler/buildrun/resources/sources/utils.go b/pkg/reconciler/buildrun/resources/sources/utils.go index 75e42a2103..5bb3375cb8 100644 --- a/pkg/reconciler/buildrun/resources/sources/utils.go +++ b/pkg/reconciler/buildrun/resources/sources/utils.go @@ -69,6 +69,30 @@ func SanitizeVolumeNameForSecretName(secretName string) string { return sanitizedName } +// SanitizeVolumeNameForStepName creates a sanitized volume name for a step +// Example: "build-and-push" -> "build-and-push", "source-git" -> "source-git" +// This ensures each step gets its own isolated writable home directory volume +func SanitizeVolumeNameForStepName(stepName string) string { + // remove forbidden characters + sanitizedName := dnsLabel1123Forbidden.ReplaceAllString(stepName, "-") + + // ensure maximum length (leave room for prefix "shp-writable-home-") + maxStepNameLength := 63 - len("shp-writable-home-") + if len(sanitizedName) > maxStepNameLength { + sanitizedName = sanitizedName[:maxStepNameLength] + } + + // trim trailing dashes because the last character must be alphanumeric + sanitizedName = strings.TrimSuffix(sanitizedName, "-") + + // ensure we have at least some content + if sanitizedName == "" { + sanitizedName = "default" + } + + return sanitizedName +} + func TaskResultName(sourceName, resultName string) string { return fmt.Sprintf("%s-source-%s-%s", PrefixParamsResultsVolumes, @@ -87,3 +111,73 @@ func FindResultValue(results []pipelineapi.TaskRunResult, sourceName, resultName return "" } + +// ensureVolume adds a volume to the TaskSpec if a volume with the same name does not already exist. +func ensureVolume(taskSpec *pipelineapi.TaskSpec, volume corev1.Volume) { + for _, v := range taskSpec.Volumes { + if v.Name == volume.Name { + return + } + } + taskSpec.Volumes = append(taskSpec.Volumes, volume) +} + +// ensureVolumeMount adds a VolumeMount to a Step if a mount with the same name does not already exist. +func ensureVolumeMount(step *pipelineapi.Step, mount corev1.VolumeMount) { + for _, m := range step.VolumeMounts { + if m.Name == mount.Name { + return + } + } + step.VolumeMounts = append(step.VolumeMounts, mount) +} + +// AppendWriteableVolumes configures writable volumes for a container step within a Tekton Task. +func AppendWriteableVolumes( + taskSpec *pipelineapi.TaskSpec, + targetStep *pipelineapi.Step, + writableHomeDir string, +) { + // Volume for /tmp (shared across containers as it's for temporary files) + tmpVolumeName := "shp-tmp-data" + ensureVolume(taskSpec, corev1.Volume{ + Name: tmpVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + ensureVolumeMount(targetStep, corev1.VolumeMount{ + Name: tmpVolumeName, + MountPath: "/tmp", + }) + + // Volume for writable home directory (unique per container) + // Generate a unique volume name based on the step name to ensure isolation + homeVolumeName := fmt.Sprintf("shp-writable-home-%s", SanitizeVolumeNameForStepName(targetStep.Name)) + ensureVolume(taskSpec, corev1.Volume{ + Name: homeVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }) + ensureVolumeMount(targetStep, corev1.VolumeMount{ + Name: homeVolumeName, + MountPath: writableHomeDir, + }) + + // Set HOME env var (override if present) + found := false + for i, env := range targetStep.Env { + if env.Name == "HOME" { + targetStep.Env[i].Value = writableHomeDir + found = true + break + } + } + if !found { + targetStep.Env = append(targetStep.Env, corev1.EnvVar{ + Name: "HOME", + Value: writableHomeDir, + }) + } +} diff --git a/pkg/reconciler/buildrun/resources/taskrun_test.go b/pkg/reconciler/buildrun/resources/taskrun_test.go index ce7be93a11..643d45c2a1 100644 --- a/pkg/reconciler/buildrun/resources/taskrun_test.go +++ b/pkg/reconciler/buildrun/resources/taskrun_test.go @@ -122,7 +122,7 @@ var _ = Describe("GenerateTaskrun", func() { }) It("should ensure top level volumes are populated", func() { - Expect(len(got.Volumes)).To(Equal(1)) + Expect(len(got.Volumes)).To(Equal(5)) }) It("should contain the shipwright system parameters", func() { diff --git a/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml b/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml index 3a9bbec4b7..9aacc58e6b 100644 --- a/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml @@ -10,7 +10,27 @@ spec: imagePullPolicy: Always workingDir: $(params.shp-source-root) securityContext: - privileged: true + runAsUser: 0 + readOnlyRootFilesystem: true + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + volumeMounts: + - name: buildah-storage + mountPath: /var/lib/containers + - name: tmp + mountPath: /tmp + - name: run + mountPath: /run + env: + - name: TMPDIR + value: /tmp command: - /bin/bash args: @@ -187,6 +207,13 @@ spec: requests: cpu: 250m memory: 65Mi + volumes: + - name: buildah-storage + emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} parameters: - name: build-args description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." diff --git a/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml b/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml index 6c19f71e40..2bad19ccd1 100644 --- a/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml @@ -10,9 +10,21 @@ spec: imagePullPolicy: Always workingDir: $(params.shp-source-root) securityContext: + runAsUser: 0 + readOnlyRootFilesystem: true capabilities: add: - "SETFCAP" + volumeMounts: + - name: buildah-storage + mountPath: /var/lib/containers + - name: tmp + mountPath: /tmp + - name: run + mountPath: /run + env: + - name: TMPDIR + value: /tmp command: - /bin/bash args: @@ -187,6 +199,13 @@ spec: requests: cpu: 250m memory: 65Mi + volumes: + - name: buildah-storage + emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} parameters: - name: build-args description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." diff --git a/samples/v1beta1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml b/samples/v1beta1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml index 144e10c837..afc5e0ab4c 100644 --- a/samples/v1beta1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml @@ -37,15 +37,21 @@ spec: image: moby/buildkit:v0.23.2-rootless imagePullPolicy: Always securityContext: - allowPrivilegeEscalation: true capabilities: add: - SETGID - SETUID seccompProfile: type: Unconfined + readOnlyRootFilesystem: true + runAsUser: 1000 + runAsGroup: 1000 workingDir: $(params.shp-source-root) env: + # This is required to align the temporary directory created by buildkit + # with the volume mount for that directory. + - name: XDG_RUNTIME_DIR + value: /home/user/.local/tmp - name: DOCKER_CONFIG value: /tekton/home/.docker - name: HOME @@ -67,6 +73,13 @@ spec: value: $(params.cache) - name: PARAM_TARGET value: $(params.target) + volumeMounts: + - name: buildkitd-1 + mountPath: /home/user/.local/share/buildkit + - name: buildkitd-2 + mountPath: /home/user/.local/tmp + - name: tmp-volume + mountPath: /tmp command: - /bin/ash args: @@ -180,3 +193,11 @@ spec: securityContext: runAsUser: 1000 runAsGroup: 1000 + volumes: + - name: tmp-volume + emptyDir: {} + - name: buildkitd-1 + emptyDir: {} + - name: buildkitd-2 + emptyDir: {} + diff --git a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml index c0c39cb502..e4242125ae 100644 --- a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml @@ -7,6 +7,12 @@ spec: volumes: - name: platform-env emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} + - name: home-dir + emptyDir: {} parameters: - name: operating-system description: The target operating system for the buildpacks build. @@ -20,7 +26,20 @@ spec: steps: - name: build-and-push image: heroku/builder:22 + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /platform/env + name: platform-env + - mountPath: /tmp + name: tmp + - mountPath: /run + name: run + - mountPath: /home + name: home-dir env: + - name: HOME + value: /home/cnb - name: CNB_TARGET_OS value: $(params.operating-system) - name: CNB_TARGET_ARCH @@ -95,9 +114,6 @@ spec: # Store the image digest grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" - volumeMounts: - - mountPath: /platform/env - name: platform-env resources: limits: cpu: 500m diff --git a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml index 249c071fa4..fddf935473 100644 --- a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml @@ -7,6 +7,12 @@ spec: volumes: - name: platform-env emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} + - name: home-dir + emptyDir: {} parameters: - name: operating-system description: The target operating system for the buildpacks build. @@ -20,7 +26,20 @@ spec: steps: - name: build-and-push image: heroku/builder:22 + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /platform/env + name: platform-env + - mountPath: /tmp + name: tmp + - mountPath: /run + name: run + - mountPath: /home + name: home-dir env: + - name: HOME + value: /home/cnb - name: CNB_TARGET_OS value: $(params.operating-system) - name: CNB_TARGET_ARCH @@ -95,9 +114,6 @@ spec: # Store the image digest grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" - volumeMounts: - - mountPath: /platform/env - name: platform-env resources: limits: cpu: 500m diff --git a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml index d6d9fd6649..b43a30ff99 100644 --- a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml @@ -7,6 +7,12 @@ spec: volumes: - name: platform-env emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} + - name: home-dir + emptyDir: {} parameters: - name: platform-api-version description: The referenced version is the minimum version that all relevant buildpack implementations support. @@ -14,7 +20,20 @@ spec: steps: - name: build-and-push image: docker.io/paketobuildpacks/builder-jammy-full:latest - env: + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /platform/env + name: platform-env + - mountPath: /tmp + name: tmp + - mountPath: /run + name: run + - mountPath: /home + name: home-dir + env: + - name: HOME + value: /home/cnb - name: CNB_PLATFORM_API value: $(params.platform-api-version) - name: PARAM_SOURCE_CONTEXT @@ -85,9 +104,6 @@ spec: # Store the image digest grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" - volumeMounts: - - mountPath: /platform/env - name: platform-env resources: limits: cpu: 500m diff --git a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml index 2374f8a135..00742ac4cd 100644 --- a/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml +++ b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml @@ -7,6 +7,12 @@ spec: volumes: - name: platform-env emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} + - name: home-dir + emptyDir: {} parameters: - name: platform-api-version description: The referenced version is the minimum version that all relevant buildpack implementations support. @@ -14,7 +20,20 @@ spec: steps: - name: build-and-push image: docker.io/paketobuildpacks/builder-jammy-full:latest - env: + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /platform/env + name: platform-env + - mountPath: /tmp + name: tmp + - mountPath: /run + name: run + - mountPath: /home + name: home-dir + env: + - name: HOME + value: /home/cnb - name: CNB_PLATFORM_API value: $(params.platform-api-version) - name: PARAM_SOURCE_CONTEXT @@ -85,9 +104,6 @@ spec: # Store the image digest grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" - volumeMounts: - - mountPath: /platform/env - name: platform-env resources: limits: cpu: 500m diff --git a/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml b/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml index 18a8e7774c..d66e674d85 100644 --- a/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml +++ b/samples/v1beta1/buildstrategy/multiarch-native-buildah/buildstrategy_multiarch_native_buildah_cr.yaml @@ -10,13 +10,25 @@ spec: overridable: true - name: additional-bins emptyDir: {} + - name: tmp + emptyDir: {} + - name: run + emptyDir: {} + - name: buildah-storage + emptyDir: {} steps: - name: prepare-build image: quay.io/centos/centos:stream9 workingDir: $(params.shp-source-root) + securityContext: + readOnlyRootFilesystem: true volumeMounts: - mountPath: /usr/local/bin name: additional-bins + - mountPath: /tmp + name: tmp + - mountPath: /run + name: run resources: requests: cpu: 100m @@ -198,8 +210,22 @@ spec: volumeMounts: - mountPath: /var/workdir name: workdir + # Temporary directories - all use buildah-temp volume + - mountPath: /tmp + name: buildah-temp + - mountPath: /var/tmp + name: buildah-temp + - mountPath: /var/cache + name: buildah-temp + # Runtime directory + - mountPath: /run + name: buildah-run + # Buildah storage + - mountPath: /var/lib/containers + name: buildah-storage securityContext: privileged: true + readOnlyRootFilesystem: true command: - bash resources: @@ -243,6 +269,12 @@ spec: volumes: - name: workdir emptyDir: {} + - name: buildah-temp + emptyDir: {} + - name: buildah-run + emptyDir: {} + - name: buildah-storage + emptyDir: {} EOF done @@ -331,11 +363,17 @@ spec: - name: wait-manifests-complete image: quay.io/centos/centos:stream9 workingDir: /tmp + securityContext: + readOnlyRootFilesystem: true volumeMounts: - mountPath: /var/oci-archive-storage name: oci-archive-storage - mountPath: /usr/local/bin name: additional-bins + - mountPath: /tmp + name: tmp + - mountPath: /run + name: run resources: requests: cpu: 50m @@ -415,6 +453,7 @@ spec: image: quay.io/containers/buildah:v1.40.1 securityContext: privileged: true + readOnlyRootFilesystem: true workingDir: /var/oci-archive-storage resources: requests: @@ -423,8 +462,22 @@ spec: limits: memory: 256Mi volumeMounts: + # Image archive storage - mountPath: /var/oci-archive-storage name: oci-archive-storage + # Temporary directories - all use tmp volume + - mountPath: /tmp + name: tmp + - mountPath: /var/tmp + name: tmp + - mountPath: /var/cache + name: tmp + # Runtime directory + - mountPath: /run + name: run + # Buildah storage + - mountPath: /var/lib/containers + name: buildah-storage command: - bash args: