驗證映像檔和非映像檔構件簽章

透過驗證映像檔簽章,在部署之前維護在 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 JSON 設定檔signing-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

  • 登錄: 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}"

如果簽章有效並使用提供的公開金鑰進行驗證,則階段將記錄證明並將階段標示為成功。