3.18. Buildah を使用したコンテナーイメージの非特権ビルド

コンテナーで root ユーザーとして OpenShift Pipelines を実行すると、コンテナープロセスとホストが他の悪意のあるリソースにさらされる可能性があります。コンテナー内の特定の root 以外のユーザーとしてワークロードを実行すると、このタイプの露出を減らすことができます。Buildah を使用してコンテナーイメージの非特権ビルドをセキュリティーで保護するには、次の手順を実行します。

  • カスタムサービスアカウント (SA) とセキュリティーコンテキスト制約 (SCC) を定義します。
  • ID が 1000build ユーザーを使用するように Buildah を設定します。
  • カスタム設定マップを使用してタスクの実行を開始するか、パイプラインの実行と統合します。

3.18.1. カスタムサービスアカウントとセキュリティーコンテキストの制約の設定

デフォルトの パイプライン SA では、namespace の範囲外のユーザー ID を使用できます。デフォルト SA への依存を減らすために、ユーザー ID 1000build ユーザーに必要なクラスターロールとロールバインディングを使用して、カスタム SA と SCC を定義できます。

手順

  • 必要なクラスターロールとロールバインディングを使用して、カスタム SA と SCC を作成します。

    例: 使用される ID が 1000 のカスタム SA および 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: false
    allowPrivilegedContainer: false
    allowedCapabilities: null
    apiVersion: security.openshift.io/v1
    defaultAddCapabilities: null
    fsGroup:
      type: MustRunAs
    groups:
    - system:cluster-admins
    priority: 10
    readOnlyRootFilesystem: false
    requiredDropCapabilities:
    - MKNOD
    runAsUser: 3
      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 4
    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 5
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: pipelines-scc-userid-1000-clusterrole
    subjects:
    - kind: ServiceAccount
      name: pipelines-sa-userid-1000

1
カスタム SA を定義します。
2
runAsUser フィールドを変更して、制限された権限に基づいて作成されたカスタム SCC を定義します。
3
カスタム SA を介してカスタム SCC にアタッチされた Pod を、ユーザー ID が 1000 として実行されるように制限します。
4
カスタム SCC を使用するクラスターロールを定義します。
5
カスタム SCC を使用するクラスターロールをカスタム SA にバインドします。

3.18.2. build ユーザーを使用するための Buildah の設定

ユーザー ID が 1000build ユーザーを使用する Buildah タスクを定義できます。

手順

  1. buildah クラスタータスクのコピーを通常のタスクとして作成します。

    $ tkn task create --from=buildah
  2. コピーした buildah タスクを編集します。

    $ oc edit task buildah

    例: build ユーザーで変更された Buildah タスク

    apiVersion: tekton.dev/v1beta1
    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
        volumeMounts:
        - name: varlibcontainers
          mountPath: /home/build/.local/share/containers
      volumes:
      - name: varlibcontainers
        emptyDir: {}

    1
    Buildah イメージの build ユーザーに対応し、明示的に ID が 1000 のユーザーとして指定してコンテナーを実行します。
    2
    ユーザー ID を表示して、プロセスがユーザー ID 1000 として実行されていることを確認します。

3.18.3. カスタムの Config Map を使用したタスク実行またはパイプライン実行の開始

カスタム Buildah クラスタータスクを定義したら、ユーザー ID が 1000build ユーザーとしてイメージをビルドする TaskRun オブジェクトを作成できます。さらに、TaskRun オブジェクトを PipelineRun オブジェクトの一部として統合できます。

手順

  1. カスタム ConfigMap および Dockerfile オブジェクトを使用して TaskRun オブジェクトを作成します。

    例: Buildah をユーザー ID 1000 として実行するタスク実行

    apiVersion: v1
    data:
      Dockerfile: |
        ARG BASE_IMG=registry.access.redhat.com/ubi8/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/v1beta1
    kind: TaskRun
    metadata:
      name: buildah-as-user-1000
    spec:
      serviceAccountName: pipelines-sa-userid-1000
      params:
      - name: IMAGE
        value: image-registry.openshift-image-registry.svc:5000/test/buildahuser
      taskRef:
        kind: Task
        name: buildah-as-user
      workspaces:
      - configMap:
          name: dockerfile 2
        name: source

    1
    Dockerfile を使用したソースの取得など実行前のタスクなしで、タスクの実行に焦点が当てられているので、Config Map を使用します。
    2
    buildah-as-user タスクのソースワークスペースとして Config Map をマウントします。
  2. (オプション) パイプラインと対応するパイプライン実行を作成します。

    例: パイプラインと対応するパイプラインの実行

    apiVersion: tekton.dev/v1beta1
    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:
          name: git-clone
          kind: ClusterTask
        workspaces:
        - name: output
          workspace: shared-workspace
        params:
        - name: url
          value: $(params.URL)
        - name: subdirectory
          value: ""
        - name: deleteExisting
          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/v1beta1
    kind: PipelineRun
    metadata:
      name: pipelinerun-buildah-as-user-1000
    spec:
      serviceAccountName: pipelines-sa-userid-1000
      params:
      - name: URL
        value: https://github.com/openshift/pipelines-vote-api
      - name: IMAGE
        value: image-registry.openshift-image-registry.svc:5000/test/buildahuser
      taskRef:
        kind: Pipeline
        name: pipeline-buildah-as-user-1000
      workspaces:
      - name: shared-workspace 3
        volumeClaimTemplate:
          spec:
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 100Mi

    1
    git-clone クラスタータスクを使用して、Dockerfile を含むソースを取得し、変更された Buildah タスクを使用してそれをビルドします。
    2
    変更された Buildah タスクを参照してください。
    3
    コントローラーによって自動的に作成される永続ボリューム要求 (PVC) を使用して、git-clone タスクと変更された Buildah タスクの間でデータを共有します。
  3. タスクの実行またはパイプラインの実行を開始します。

3.18.4. 非特権ビルドの制限

非特権ビルドのプロセスは、ほとんどの Dockerfile オブジェクトで機能します。ただし、ビルドが失敗する原因となる既知の制限がいくつかあります。

  • --mount=type=cache オプションの使用は、必要となるパーミッションの問題が原因で失敗する場合があります。詳細は、このアーティクル を参照してください。
  • --mount=type=secret オプションの使用は失敗します。リソースのマウントには、カスタム SCC によって提供されない追加の機能が必要になるためです。