你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 Notation 和可信签名在 GitHub 工作流中验证容器镜像

本文是一系列关于确保容器映像和其他开放容器计划(OCI)项目的完整性和真实性的一部分。 对于完整情况,请从概述开始,该 概述解释了签名为何重要并概述了各种方案。

可以在两种方案中使用本指南:

  • 使用签名的映像:使用 Notation 和受信任签名,验证其他团队或组织已签名的容器映像。
  • 验证自己的映像:如果自行发布映像,请先使用 GitHub 工作流表示法命令行接口(CLI)对其进行签名。 然后按照本指南验证签名。

在这篇文章中,你将学会如何:

  • 配置 GitHub 工作流。
  • 使用受信任签名和适用于 Notation 的 GitHub Actions 验证容器映像是否已签名。

先决条件

  • 包含已签名镜像的 容器注册表
  • 用于存储工作流文件、信任策略和信任存储的 GitHub 存储库。

从 Azure 到 GitHub 进行身份验证

根据 使用 GitHub Actions 连接到 Azure,必须先在工作流中使用 Azure 登录操作进行身份验证,然后才能运行 Azure CLI 或 Azure PowerShell 命令。 Azure 登录作支持多种身份验证方法。

在本指南中,您将使用 OpenID Connect (OIDC) 进行登录,采用用户分配的托管标识,并遵循 使用 OpenID Connect 的 Azure 登录操作中的步骤。

  1. 创建用户分配的托管标识。 如果你有现有的托管标识,请跳过此步骤。

    az login
    az identity create -g <identity-resource-group> -n <identity-name>
    

  1. 获取托管标识的客户端 ID:

    CLIENT_ID=$(az identity show -g <identity-resource-group> -n <identity-name> --query clientId -o tsv)
    

  1. 将角色分配给用于访问 Azure 容器注册表的托管标识。

    对于未使用基于属性的访问控制(ABAC)启用的注册表,请分配 AcrPull 角色:

    ACR_SCOPE=/subscriptions/<subscription-id>/resourceGroups/<acr-resource-group>
    az role assignment create --assignee $CLIENT_ID --scope $ACR_SCOPE --role "acrpush" --role "acrpull"
    

    对于已启用 ABAC 的注册表,请分配 Container Registry Repository Reader 角色:

    ACR_SCOPE=/subscriptions/<subscription-id>/resourceGroups/<acr-resource-group>
    az role assignment create --assignee $CLIENT_ID --scope $ACR_SCOPE --role "Container Registry Repository Reader" --role "Container Registry Repository Writer"
    

  1. 配置 GitHub 以认证您的身份。 请按照 配置用户分配的托管标识以信任外部标识提供者 的步骤进行操作。

  2. 按照 为存储库创建机密 来创建 GitHub 机密。

    将托管标识值映射到这些机密:

    GitHub 机密 托管标识值
    AZURE_CLIENT_ID 客户 ID
    AZURE_SUBSCRIPTION_ID 订阅编号
    AZURE_TENANT_ID 目录(租户)ID

准备信任存储和信任策略

要完成验证,需要在存储库中包含 Notary Project 的信任存储和信任策略

创建信任存储

信任存储(.github/truststore/)包含证书颁发机构(CA)证书和验证所需的时间戳颁发机构(TSA)根证书。

下载 受信任的签名根证书 并将其存储在 ca 目录中:

curl -o .github/truststore/x509/ca/mycerts/msft-identity-verification-root-cert-2020.crt \
    "https://www.microsoft.com/pkiops/certs/Microsoft%20Enterprise%20Identity%20Verification%20Root%20Certificate%20Authority%202020.crt"

下载 受信任的签名 TSA 根证书 并将其存储在 tsa 目录中:

curl -o .github/truststore/x509/tsa/mytsacerts/msft-identity-verification-tsa-root-cert-2020.crt \
  "http://www.microsoft.com/pkiops/certs/microsoft%20identity%20verification%20root%20certificate%20authority%202020.crt"

创建信任策略

信任策略 (.github/trustpolicy/trustpolicy.json) 定义哪些标识和 CA 受信任。

以下是一个示例 trustpolicy.json。 将存储库 URI、信任存储名称和受信任签名证书配置文件使用者替换为你的值。

{
 "version": "1.0",
 "trustPolicies": [
    {
         "name": "mypolicy",
         "registryScopes": [ "myregistry.azurecr.io/myrepo1","myregistry.azurecr.io/myrepo2" ],
         "signatureVerification": {
             "level" : "strict"
         },
         "trustStores": [ "ca:mycerts", "tsa:mytsacerts" ],
         "trustedIdentities": [
           "x509.subject: C=US, ST=WA, L=Seattle, O=MyCompany.io, OU=Tools"
         ]
     }
 ]
}

确认目录结构

存储库应如以下示例所示:

.github/
├── trustpolicy/
│   └── trustpolicy.json
└── truststore/
    └── x509/
        ├── ca/
        │   └── mycerts/
        │       └── msft-identity-verification-root-cert-2020.crt
        └── tsa/
            └── mytsacerts/
                └── msft-identity-verification-tsa-root-cert-2020.crt

创建 GitHub Actions 工作流

身份验证和信任配置准备就绪后,创建工作流:

  1. 在存储库中创建目录 .github/workflows (如果不存在)。

  2. 创建新的工作流文件;例如, verify-with-trusted-signing.yml.

  3. 将以下工作流模板复制到文件中。

    展开以查看验证工作流模板。
    name: notation-verify-with-trusted-signing
    
    on:
      push:
    
    env:
      ACR_LOGIN_SERVER: <registry-name>.azurecr.io                      # example: myRegistry.azurecr.io
      ACR_REPO_NAME: <repository-name>                                  # example: myRepo
      IMAGE_TAG: <image-tag>                                            # example: v1
      #IMAGE_DIGEST: <image-digest>                                     # example: sha256:xxx
    jobs:
      notation-verify:
        runs-on: ubuntu-latest
        permissions:
          id-token: write
          contents: read
        steps:
          - name: Checkout
            uses: actions/checkout@v3
          # Log in to Azure with your service principal secret
          # - name: Azure login
          #  uses: Azure/login@v1
          #  with:
          #    creds: ${{ secrets.AZURE_CREDENTIALS }}
          # If you're using OIDC and federated credentials, make sure to replace the preceding step with the following:
          - name: Azure login
            uses: Azure/login@v2
            with:
              client-id: ${{ secrets.AZURE_CLIENT_ID }}
              tenant-id: ${{ secrets.AZURE_TENANT_ID }}
              subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    
          # Log in to your container registry
          - name: ACR login
            run: |
                az acr login --name ${{ env.ACR_LOGIN_SERVER }}
    
          # Set up the Notation CLI
          - name: setup notation
            uses: notaryproject/notation-action/setup@v1.2.2
    
          # Verify the OCI artifact, such as container images
          - name: verify OCI artifact
            uses: notaryproject/notation-action/verify@v1
            with:
              target_artifact_reference: ${{ env.ACR_LOGIN_SERVER }}/${{ env.ACR_REPO_NAME }}:${{ env.IMAGE_TAG }}
              # Alternatively, use the image digest
              # target_artifact_reference: ${{ env.ACR_LOGIN_SERVER }}/${{ env.ACR_REPO_NAME }}@${{ env.IMAGE_DIGEST }}
              trust_policy: .github/trustpolicy/trustpolicy.json
              trust_store: .github/truststore
    
  4. 使用自己的注册表、存储库和映像标记/摘要更新环境变量。 保存并提交文件。

触发 GitHub Actions 工作流

推送触发示例工作流。 若要启动作业,请将工作流文件提交到存储库。

可以查看工作流日志以确认作业成功完成。 例如,检查是否导入信任策略,加载信任存储中的证书,并验证签名。