×

在容器上以 root 用户身份运行 OpenShift Pipelines 可能会将容器进程和主机暴露给其他潜在的恶意资源。您可以通过在容器中以特定非 root 用户身份运行工作负载来减少此类风险。

在大多数情况下,您可以通过为构建镜像创建自定义任务并在该任务中配置用户命名空间来在没有 root 权限的情况下运行 Buildah。

如果使用此配置无法成功构建镜像,则可以使用自定义服务帐户 (SA) 和安全上下文约束 (SCC) 定义;但是,如果使用此选项,则必须启用 Buildah 步骤以提升其权限 (allowPrivilegeEscalation: true)。

通过配置用户命名空间以非 root 用户身份运行 Buildah

配置用户命名空间是在任务中以非 root 用户身份运行 Buildah 的最简单方法。但是,某些镜像可能无法使用此选项进行构建。

前提条件
  • 您已安装 `oc` 命令行实用程序。

步骤
  1. 要创建 `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 -
  2. 通过输入以下命令来编辑复制的 `buildah` 任务:

    $ oc edit task buildah-as-user

    在新任务中,创建 `annotations` 和 `stepTemplate` 部分,如下例所示:

    `buildah-as-user` 任务的示例添加内容
    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`。
  3. 使用新的 `buildah-as-user` 任务在您的管道中构建镜像。

通过定义自定义 SA 和 SCC 以非 root 用户身份运行 Buildah

要使用 Buildah 作为非 root 用户运行容器镜像的构建,您可以执行以下步骤:

  • 定义自定义服务帐户 (SA) 和安全上下文约束 (SCC)。

  • 配置 Buildah 使用 ID 为 1000build 用户。

  • 启动使用自定义配置映射的任务运行,或将其与流水线运行集成。

配置自定义服务账户和安全上下文约束

默认的 pipeline 服务账户允许使用命名空间范围外的用户 ID。为了减少对默认服务账户的依赖,您可以定义一个自定义服务账户和 SCC,其中包含 build 用户(用户 ID 为 1000)所需的集群角色和角色绑定。

目前,需要启用 allowPrivilegeEscalation 设置才能使 Buildah 在容器中成功运行。使用此设置,Buildah 可以在以非 root 用户身份运行时利用 SETUIDSETGID 功能。

步骤
  • 创建具有必要集群角色和角色绑定的自定义服务账户和 SCC。

    示例:用户 ID 为 1000 的自定义服务账户和 SCC
    apiVersion: 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 用户身份运行时利用 SETUIDSETGID 功能。
4 限制通过自定义服务账户附加自定义 SCC 的任何 Pod 以用户 ID 1000 运行。
5 定义使用自定义 SCC 的集群角色。
6 将使用自定义 SCC 的集群角色绑定到自定义服务账户。

配置 Buildah 使用 build 用户

您可以定义一个 Buildah 任务来使用用户 ID 为 1000build 用户。

步骤
  1. 创建 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 -
  2. 编辑复制的 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 为 1000build 用户身份构建镜像。此外,您可以将 TaskRun 对象作为 PipelineRun 对象的一部分集成。

步骤
  1. 创建具有自定义 ConfigMapDockerfile 对象的 TaskRun 对象。

    示例:以用户 ID 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 任务的源工作区挂载。
  2. (可选) 创建流水线和相应的流水线运行。

    示例:流水线和相应的流水线运行
    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 任务之间共享数据。
  3. 启动任务运行或流水线运行。

无权限构建的限制

无权限构建的过程适用于大多数 Dockerfile 对象。但是,一些已知的限制可能会导致构建失败。

  • 由于缺少必要的权限,使用 --mount=type=cache 选项可能会失败。更多信息,请参见这篇 文章

  • 使用 --mount=type=secret 选项会失败,因为挂载资源需要自定义 SCC 未提供的附加功能。