$ 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-userbuild 用户修改后的 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 未提供的附加功能。