$ oc get task buildah -n openshift-pipelines -o yaml | yq '. |= (del .metadata |= with_entries(select(.key == "name" )))' | yq '.kind="Task"' | yq '.metadata.name="buildah-as-user"' | oc create -f -
在容器上以 root 用户身份运行 OpenShift Pipelines 可能会将容器进程和主机暴露给其他潜在的恶意资源。您可以通过在容器中以特定非 root 用户身份运行工作负载来减少此类风险。
在大多数情况下,您可以通过为构建镜像创建自定义任务并在该任务中配置用户命名空间来在没有 root 权限的情况下运行 Buildah。
如果使用此配置无法成功构建镜像,则可以使用自定义服务帐户 (SA) 和安全上下文约束 (SCC) 定义;但是,如果使用此选项,则必须启用 Buildah 步骤以提升其权限 (allowPrivilegeEscalation: true
)。
配置用户命名空间是在任务中以非 root 用户身份运行 Buildah 的最简单方法。但是,某些镜像可能无法使用此选项进行构建。
您已安装 `oc` 命令行实用程序。
要创建 `openshift-pipelines` 命名空间中提供的 `buildah` 任务的副本,并将副本的名称更改为 `buildah-as-user`,请输入以下命令:
$ oc get task buildah -n openshift-pipelines -o yaml | yq '. |= (del .metadata |= with_entries(select(.key == "name" )))' | yq '.kind="Task"' | yq '.metadata.name="buildah-as-user"' | oc create -f -
通过输入以下命令来编辑复制的 `buildah` 任务:
$ oc edit task buildah-as-user
在新任务中,创建 `annotations` 和 `stepTemplate` 部分,如下例所示:
apiVersion: tekton.dev/v1
kind: Task
metadata:
annotations:
io.kubernetes.cri-o.userns-mode: 'auto:size=65536;map-to-root=true'
io.openshift.builder: 'true'
name: assemble-containerimage
namespace: pipeline-namespace
spec:
description: This task builds an image.
# ...
stepTemplate:
env:
- name: HOME
value: /tekton/home
image: $(params.builder-image)
imagePullPolicy: IfNotPresent
name: ''
resources:
limits:
cpu: '1'
memory: 4Gi
requests:
cpu: 100m
memory: 2Gi
securityContext:
capabilities:
add:
- SETFCAP
runAsNonRoot: true
runAsUser: 1000 (1)
workingDir: $(workspaces.working-directory.path)
# ...
1 | `runAsUser:` 设置并非严格必要,因为使用了 `podTemplate`。 |
使用新的 `buildah-as-user` 任务在您的管道中构建镜像。
要使用 Buildah 作为非 root 用户运行容器镜像的构建,您可以执行以下步骤:
定义自定义服务帐户 (SA) 和安全上下文约束 (SCC)。
配置 Buildah 使用 ID 为 1000
的 build
用户。
启动使用自定义配置映射的任务运行,或将其与流水线运行集成。
默认的 pipeline
服务账户允许使用命名空间范围外的用户 ID。为了减少对默认服务账户的依赖,您可以定义一个自定义服务账户和 SCC,其中包含 build
用户(用户 ID 为 1000
)所需的集群角色和角色绑定。
目前,需要启用 |
创建具有必要集群角色和角色绑定的自定义服务账户和 SCC。
1000
的自定义服务账户和 SCCapiVersion: v1
kind: ServiceAccount
metadata:
name: pipelines-sa-userid-1000 (1)
---
kind: SecurityContextConstraints
metadata:
annotations:
name: pipelines-scc-userid-1000 (2)
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegeEscalation: true (3)
allowPrivilegedContainer: false
allowedCapabilities: null
apiVersion: security.openshift.io/v1
defaultAddCapabilities: null
fsGroup:
type: MustRunAs
groups:
- system:cluster-admins
priority: 10
readOnlyRootFilesystem: false
requiredDropCapabilities:
- MKNOD
- KILL
runAsUser: (4)
type: MustRunAs
uid: 1000
seLinuxContext:
type: MustRunAs
supplementalGroups:
type: RunAsAny
users: []
volumes:
- configMap
- downwardAPI
- emptyDir
- persistentVolumeClaim
- projected
- secret
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pipelines-scc-userid-1000-clusterrole (5)
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- pipelines-scc-userid-1000
resources:
- securitycontextconstraints
verbs:
- use
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pipelines-scc-userid-1000-rolebinding (6)
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pipelines-scc-userid-1000-clusterrole
subjects:
- kind: ServiceAccount
name: pipelines-sa-userid-1000
1 | 定义自定义服务账户。 |
2 | 定义基于受限权限创建的自定义 SCC,并修改 runAsUser 字段。 |
3 | 目前,需要启用 allowPrivilegeEscalation 设置才能使 Buildah 在容器中成功运行。使用此设置,Buildah 可以在以非 root 用户身份运行时利用 SETUID 和 SETGID 功能。 |
4 | 限制通过自定义服务账户附加自定义 SCC 的任何 Pod 以用户 ID 1000 运行。 |
5 | 定义使用自定义 SCC 的集群角色。 |
6 | 将使用自定义 SCC 的集群角色绑定到自定义服务账户。 |
build
用户您可以定义一个 Buildah 任务来使用用户 ID 为 1000
的 build
用户。
创建 openshift-pipelines
命名空间中提供的 buildah
任务的副本;将副本名称更改为 buildah-as-user
。
$ oc get task buildah -n openshift-pipelines -o yaml | yq '. |= (del .metadata |= with_entries(select(.key == "name" )))' | yq '.kind="Task"' | yq '.metadata.name="buildah-as-user"' | oc create -f -
编辑复制的 buildah
任务。
$ oc edit task buildah-as-user
build
用户修改后的 Buildah 任务apiVersion: tekton.dev/v1
kind: Task
metadata:
name: buildah-as-user
spec:
description: >-
Buildah task builds source into a container image and
then pushes it to a container registry.
Buildah Task builds source into a container image using Project Atomic's
Buildah build tool.It uses Buildah's support for building from Dockerfiles,
using its buildah bud command.This command executes the directives in the
Dockerfile to assemble a container image, then pushes that image to a
container registry.
params:
- name: IMAGE
description: Reference of the image buildah will produce.
- name: BUILDER_IMAGE
description: The location of the buildah builder image.
default: registry.redhat.io/rhel8/buildah@sha256:99cae35f40c7ec050fed3765b2b27e0b8bbea2aa2da7c16408e2ca13c60ff8ee
- name: STORAGE_DRIVER
description: Set buildah storage driver
default: vfs
- name: DOCKERFILE
description: Path to the Dockerfile to build.
default: ./Dockerfile
- name: CONTEXT
description: Path to the directory to use as context.
default: .
- name: TLSVERIFY
description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry)
default: "true"
- name: FORMAT
description: The format of the built container, oci or docker
default: "oci"
- name: BUILD_EXTRA_ARGS
description: Extra parameters passed for the build command when building images.
default: ""
- description: Extra parameters passed for the push command when pushing images.
name: PUSH_EXTRA_ARGS
type: string
default: ""
- description: Skip pushing the built image
name: SKIP_PUSH
type: string
default: "false"
results:
- description: Digest of the image just built.
name: IMAGE_DIGEST
type: string
workspaces:
- name: source
steps:
- name: build
securityContext:
runAsUser: 1000 (1)
image: $(params.BUILDER_IMAGE)
workingDir: $(workspaces.source.path)
script: |
echo "Running as USER ID `id`" (2)
buildah --storage-driver=$(params.STORAGE_DRIVER) bud \
$(params.BUILD_EXTRA_ARGS) --format=$(params.FORMAT) \
--tls-verify=$(params.TLSVERIFY) --no-cache \
-f $(params.DOCKERFILE) -t $(params.IMAGE) $(params.CONTEXT)
[[ "$(params.SKIP_PUSH)" == "true" ]] && echo "Push skipped" && exit 0
buildah --storage-driver=$(params.STORAGE_DRIVER) push \
$(params.PUSH_EXTRA_ARGS) --tls-verify=$(params.TLSVERIFY) \
--digestfile $(workspaces.source.path)/image-digest $(params.IMAGE) \
docker://$(params.IMAGE)
cat $(workspaces.source.path)/image-digest | tee /tekton/results/IMAGE_DIGEST
volumeMounts:
- name: varlibcontainers
mountPath: /home/build/.local/share/containers (3)
volumes:
- name: varlibcontainers
emptyDir: {}
1 | 显式地以用户 ID 1000 运行容器,这对应于 Buildah 镜像中的 build 用户。 |
2 | 显示用户 ID 以确认进程正在以用户 ID 1000 运行。 |
3 | 您可以根据需要更改卷挂载的路径。 |
定义自定义 Buildah 任务后,您可以创建一个 TaskRun
对象,该对象以用户 ID 为 1000
的 build
用户身份构建镜像。此外,您可以将 TaskRun
对象作为 PipelineRun
对象的一部分集成。
创建具有自定义 ConfigMap
和 Dockerfile
对象的 TaskRun
对象。
1000
运行 Buildah 的任务运行apiVersion: v1
data:
Dockerfile: |
ARG BASE_IMG=registry.access.redhat.com/ubi9/ubi
FROM $BASE_IMG AS buildah-runner
RUN dnf -y update && \
dnf -y install git && \
dnf clean all
CMD git
kind: ConfigMap
metadata:
name: dockerfile (1)
---
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: buildah-as-user-1000
spec:
taskRunTemplate:
serviceAccountName: pipelines-sa-userid-1000 (2)
params:
- name: IMAGE
value: image-registry.openshift-image-registry.svc:5000/test/buildahuser
taskRef:
kind: Task
name: buildah-as-user
workspaces:
- configMap:
name: dockerfile (3)
name: source
1 | 使用配置映射,因为重点是任务运行,没有任何先前任务使用 Dockerfile 获取一些源代码。 |
2 | 您创建的服务账户的名称。 |
3 | 将配置映射作为 buildah-as-user 任务的源工作区挂载。 |
(可选) 创建流水线和相应的流水线运行。
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: pipeline-buildah-as-user-1000
spec:
params:
- name: IMAGE
- name: URL
workspaces:
- name: shared-workspace
- name: sslcertdir
optional: true
tasks:
- name: fetch-repository (1)
taskRef:
resolver: cluster
params:
- name: kind
value: task
- name: name
value: git-clone
- name: namespace
value: openshift-pipelines
workspaces:
- name: output
workspace: shared-workspace
params:
- name: URL
value: $(params.URL)
- name: SUBDIRECTORY
value: ""
- name: DELETE_EXISTING
value: "true"
- name: buildah
taskRef:
name: buildah-as-user (2)
runAfter:
- fetch-repository
workspaces:
- name: source
workspace: shared-workspace
- name: sslcertdir
workspace: sslcertdir
params:
- name: IMAGE
value: $(params.IMAGE)
---
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: pipelinerun-buildah-as-user-1000
spec:
taskRunSpecs:
- pipelineTaskName: buildah
taskServiceAccountName: pipelines-sa-userid-1000 (3)
params:
- name: URL
value: https://github.com/openshift/pipelines-vote-api
- name: IMAGE
value: image-registry.openshift-image-registry.svc:5000/test/buildahuser
pipelineRef:
name: pipeline-buildah-as-user-1000
workspaces:
- name: shared-workspace (4)
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
1 | 使用 git-clone 任务获取包含 Dockerfile 的源代码并使用修改后的 Buildah 任务构建它。 |
2 | 参考修改后的 Buildah 任务。 |
3 | 为 Buildah 任务使用您创建的服务账户。 |
4 | 使用控制器自动创建的持久卷声明 (PVC) 在 git-clone 任务和修改后的 Buildah 任务之间共享数据。 |
启动任务运行或流水线运行。
无权限构建的过程适用于大多数 Dockerfile
对象。但是,一些已知的限制可能会导致构建失败。
由于缺少必要的权限,使用 --mount=type=cache
选项可能会失败。更多信息,请参见这篇 文章。
使用 --mount=type=secret
选项会失败,因为挂载资源需要自定义 SCC 未提供的附加功能。