验证映像和非映像工件特征符

通过验证映像签名,在部署之前维护在 Continuous Integration (CI) 管道中构建的映像的完整性。

准备工作

在开始使用图像验证功能之前,请确保您已满足以下先决条件。

  • 您必须具有 GPG 公用密钥。 有关生成 GPG 密钥的帮助,请参阅 文档
  • 必须使用基本 64 位编码的 GPG 公用密钥添加环境变量 code-signing-certificate
  • 您必须配置注册表凭据,以便在验证过程中访问容器镜像(请参阅 “配置注册表凭据” )。

验证映像

新的 prod-verify-artifact 阶段将验证 Continuous Delivery (CD) 管道中映像的特征符。 此阶段执行以下步骤:

  1. 将用户提供的编码 GPG 公用密钥解码为临时文件。

  2. 使用公用密钥创建 Docker 容器策略 (/etc/containers/policy.json)。

     {
       "default": [
         {
           "type": "reject"
         }
       ],
       "transports": {
         "docker-daemon": {
           "": [
             {
               "type": "reject"
             }
           ]
         },
         "docker": {
           "": [
             {
               "type": "signedBy",
               "keyType": "GPGKeys",
               "keyPath": "/tmp/GPGPublicKey"
             }
           ]
         }
       }
     }
    
  3. 通过使用 Skopeo 通过容器策略来拉取映像,检索每个工件的工件列表。

        skopeo copy docker://"${image}" dir:"${tmp_sign_dir}" --src-creds iamapikey:"${ibmcloud_api_key}"
    

如果签名有效并由用户提供的公用密钥进行验证,那么映像拉取成功。

配置注册表凭据以供验证

在验证容器镜像签名时,管道需要凭据来对容器注册表进行身份验证,并访问已签名的镜像。 DevSecOps 管道支持运行时动态凭据解析,允许您通过多种方式配置凭据,并具备自动回退机制。

凭证解析层次结构

该管道在运行时会根据以下优先级顺序动态解析用户名和 API 密钥凭据:

API 密钥解析顺序:

  1. 特定于命名空间的 API 密钥signing-token-apikey-{registry}-{namespace} (密钥)
  2. 注册表专用 API 密钥signing-token-apikey-{registry} (密钥)
  3. Docker 配置 JSONsigning-dockerconfigjson (密钥)
  4. ICR 特定的备用方案
    • ciso-ibmcloud-api-key (秘密)
    • ibmcloud-api-key (秘密)

用户名解析顺序:

  1. 命名空间专用用户名signing-token-username-{registry}-{namespace} (环境变量)
  2. 注册表专用用户名signing-token-username-{registry} (环境变量)
  3. 默认值iamapikey (如果未配置用户名)

其中:

  • {registry} 是注册表的主机名(例如:us.icr.iode.icr.io
  • {namespace} 这是完整的命名空间路径,其中斜杠和点已被下划线替换(例如:my_namespace_path

配置命名空间专用凭据

为了实现精细的访问控制,您可以配置针对特定注册表命名空间的凭据:

API密钥(密钥)signing-token-apikey-{registry}-{namespace}

用户名(环境变量)signing-token-username-{registry}-{namespace}

示例:关于图片 us.icr.io/my-namespace/my-app:latest

  • registry: us.icr.io
  • 命名空间:my-namespace
  • API密钥密钥:signing-token-apikey-us.icr.io-my_namespace
  • 用户名环境变量:signing-token-username-us.icr.io-my_namespace
  • 如果未提供用户名,则默认为:iamapikey

配置注册表专用凭据

若要在注册表的所有命名空间中实现更广泛的访问:

API密钥(密钥)signing-token-apikey-{registry}

用户名(环境变量)signing-token-username-{registry}

示例:对于任何位于 us.icr.io

  • API密钥密钥:signing-token-apikey-us.icr.io
  • 用户名环境变量:signing-token-username-us.icr.io
  • 如果未提供用户名,则默认为:iamapikey

配置 Docker 的JSON配置文件

您可以提供一个包含多个注册表凭据的 base64-encoded Docker 配置 JSON 文件:

秘密名称signing-dockerconfigjson

格式:Base64-encoded 符合 Docker 网站上 config.json 格式的 JSON:

{
  "auths": {
    "us.icr.io": {
      "username": "iamapikey",
      "password": "your-api-key"
    },
    "us.icr.io/my-namespace": {
      "username": "iamapikey",
      "password": "namespace-specific-key"
    }
  }
}

该管道会优先匹配最具体的路径,从而允许在 Docker 配置中进行命名空间级别的覆盖。

示例配置

关于图片 us.icr.io/production/my-app:v1.0.0

选项 1:命名空间专用(建议用于生产环境)

  • API密钥密钥:signing-token-apikey-us.icr.io-production = your-namespace-api-key
  • 用户名环境变量(可选):signing-token-username-us.icr.io-production = iamapikey
  • 如果未指定用户名,则默认为 iamapikey

选项 2:全局注册表

  • API密钥密钥:signing-token-apikey-us.icr.io = your-registry-api-key
  • 用户名环境变量(可选):signing-token-username-us.icr.io = iamapikey
  • 如果未指定用户名,则默认为 iamapikey

选项 3:Docker 配置 JSON

  • 秘诀:signing-dockerconfigjson = base64-encoded-docker-config
  • 用户名是从 Docker 的配置 JSON 中提取的

选项 4:IBM Cloud (默认值,ICR 模式下自动处理)

  • API密钥密钥:ibmcloud-api-key = your-ibmcloud-api-key
  • 用户名默认为 iamapikey

验证非图像工件

在 DevSecOps 管道中,签名构建产物的签名需经过验证。 本节概述了用户在继续工件验证之前必须满足的先决条件。

准备工作

在可以使用图像验证之前,请确保您具有以下先决条件。

  1. 修改管道配置以启用验证过程。 将以下代码片段添加到你的 .pipeline-config.yaml 文件中。

    verify-artifact:
      image: icr.io/continuous-delivery/pipeline/image-signing:1.0.0@sha256:e9d8e354668ba3d40be2aaee08298d2aa7f0e1c8a1829cca4094ec93830e3e6a
      image_pull_policy: IfNotPresent
      abort_on_failure: false
      dind: true
      script: |
        #!/usr/bin/env bash
        source /opt/commons/verify-artifact/verify_non_image_artifact.sh
    
  2. 下载工件并将其存储在管道运行时中。

    在调用 verify-artifact 阶段之前,请下载所需工件并将其存储在 Cocoa 运行时中。 默认情况下,list_artifacts 集合中列出的所有工件都会经过验证。 使用 skip-sign-artifact-type 文本属性,可跳过对指定工件类型(例如:log、report、documentation)的图像签名验证。 以下示例代码演示了如何从 Cloud Object Storage 下载一个构建产物,并将其保存到 Cocoa 运行时中:

    #!/usr/bin/env bash
    
    export SECRET_PATH="/config/ibmcloud-api-key"
    . "${ONE_PIPELINE_PATH}"/iam/get_token
    
    SKIP_SIGN_ARTIFACTS_TYPE="$(get_env skip-sign-artifact-type "")"
    IFS=';' read -ra ARTIFACT_LIST <<<"$SKIP_SIGN_ARTIFACTS_TYPE"
    
    list_artifacts | while IFS= read -r artifact; do
    
       type="$(load_artifact "$artifact" "type")"
    
       if [[ ! "${ARTIFACT_LIST[@]}" =~ "$type" ]] && [[ "$type" != "image" ]]; then
    
          inventory_entry="$(load_artifact "$artifact" "inventory-entry")"
          inventory_entry=${inventory_entry///artifacts/$WORKSPACE}
          artifact_url=$(jq -r .'app_artifacts.artifact_url' ${inventory_entry})
          echo "downloading the artifact  ${artifact_url}"
          curl -H "Authorization: bearer ${IAM_ACCESS_TOKEN}" --output outputfile ${artifact_url}
          save_file "${artifact}" outputfile
    
       fi
    done
    

验证工件

在工件验证过程中,将用户提供的 GPG 公用密钥导入到 GPG 密钥环中。 将验证 list_artifacts 集合中列出的所有工件。 该阶段尝试从清单中检索签名并执行以下验证:

gpg --verify  "${signature}" "${artifactName}"

如果签名有效并使用提供的公用密钥进行验证,那么阶段将记录证据并将阶段标记为成功。