使用自签名证书通过表示法和 Azure Key Vault 对容器映像进行签名

为容器映像签名是一个确保其真实性和完整性的过程。 这是通过将数字签名添加到容器映像来实现的,该签名可在部署期间进行验证。 签名有助于验证映像是否来自受信任的发布者,并且尚未修改。 Notation 是由 Notary Project 社区开发并由 Microsoft 提供技术支持的一个开源供应链安全工具,它支持对容器映像及其他项目进行签名和验证。 Azure Key Vault (AKV) 用于存储证书,其签名密钥可供支持 Notation AKV 插件 (azure-kv) 的 Notation 用来对容器映像及其他项目进行签名和验证。 Azure 容器注册表 (ACR) 允许将签名附加到容器映像和其他项目,以及查看这些签名。

本教程的内容:

  • 安装 Notation CLI 和 AKV 插件
  • 在 AKV 中创建自签名证书
  • 使用 Azure 任务生成并推送容器映像
  • 使用 Notation CLI 和 AKV 插件为容器映像签名
  • 使用 Notation CLI 根据签名验证容器映像
  • 时间戳

先决条件

安装 Notation CLI 和 AKV 插件

  1. 在 Linux amd64 环境中安装 Notation v1.2.0。 按照 Notation 安装指南下载适用于其他环境的包。

    # Download, extract and install
    curl -Lo notation.tar.gz https://github.com/notaryproject/notation/releases/download/v1.2.0/notation_1.2.0_linux_amd64.tar.gz
    tar xvzf notation.tar.gz
    
    # Copy the Notation binary to the desired bin directory in your $PATH, for example
    cp ./notation /usr/local/bin
    
  2. 在 Linux amd64 环境上安装 Notation Azure Key Vault 插件 azure-kv v1.2.0。

    注意

    可以在插件的发布页上找到 Notation Azure Key Vault 插件的 URL 和 SHA256 校验和。

    notation plugin install --url https://github.com/Azure/notation-azure-kv/releases/download/v1.2.0/notation-azure-kv_1.2.0_linux_amd64.tar.gz --sha256sum 06bb5198af31ce11b08c4557ae4c2cbfb09878dfa6b637b7407ebc2d57b87b34
    
  3. 列出可用的插件,并确认版本为 1.2.0azure-kv 插件是否已包含在列表中。

    notation plugin ls
    

配置环境变量

注意

为便于执行教程中的命令,请提供 Azure 资源的值来匹配现有的 ACR 和 AKV 资源。

  1. 配置 AKV 资源名。

    AKV_SUB_ID=myAkvSubscriptionId
    AKV_RG=myAkvResourceGroup
    # Name of the existing AKV used to store the signing keys
    AKV_NAME=myakv
    # Name of the certificate created in AKV
    CERT_NAME=wabbit-networks-io
    CERT_SUBJECT="CN=wabbit-networks.io,O=Notation,L=Seattle,ST=WA,C=US"
    CERT_PATH=./${CERT_NAME}.pem
    
  2. 配置 ACR 和映像资源名。

    ACR_SUB_ID=myAcrSubscriptionId
    ACR_RG=myAcrResourceGroup
    # Name of the existing registry example: myregistry.azurecr.cn
    ACR_NAME=myregistry
    # Existing full domain of the ACR
    REGISTRY=$ACR_NAME.azurecr.cn
    # Container name inside ACR where image will be stored
    REPO=net-monitor
    TAG=v1
    IMAGE=$REGISTRY/${REPO}:$TAG
    # Source code directory containing Dockerfile to build
    IMAGE_SOURCE=https://github.com/wabbit-networks/net-monitor.git#main
    

使用 Azure CLI 登录

az cloud set -n AzureChinaCloud
az login
# az cloud set -n AzureCloud   //means return to Public Azure.

若要详细了解 Azure CLI 及其登录方式,请参阅使用 Azure CLI 登录

对 ACR 和 AKV 的安全访问权限

使用 ACR 和 AKV 时,必须授予适当的权限以确保安全性和受控访问。 可以根据特定方案为不同的实体(例如用户主体、服务主体或托管标识)授予访问权限。 在本教程中,访问权限授予给已登录的 Azure 用户。

授予对 ACR 的访问权限

在 ACR 中为容器映像签名需要 AcrPullAcrPush 角色。

  1. 设置包含 ACR 资源的订阅

    az account set --subscription $ACR_SUB_ID
    
  2. 分配角色

    USER_ID=$(az ad signed-in-user show --query id -o tsv)
    az role assignment create --role "AcrPull" --role "AcrPush" --assignee $USER_ID --scope "/subscriptions/$ACR_SUB_ID/resourceGroups/$ACR_RG/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME"
    

授予对 AKV 的访问权限

在本部分中,我们将探讨用于授与 AKV 访问权限的两个选项。

使用自签名证书进行签名需要以下角色:

  • Key Vault Certificates Officer,用于创建和读取证书
  • Key Vault Certificates User,用于读取现有证书
  • Key Vault Crypto User,用于对操作进行签名

若要了解有关使用 Azure RBAC 进行 Key Vault 访问的详细信息,请参阅使用 Azure RBAC 管理访问权限

  1. 设置包含 AKV 资源的订阅

    az account set --subscription $AKV_SUB_ID
    
  2. 分配角色

    USER_ID=$(az ad signed-in-user show --query id -o tsv)
    az role assignment create --role "Key Vault Certificates Officer" --role "Key Vault Crypto User" --assignee $USER_ID --scope "/subscriptions/$AKV_SUB_ID/resourceGroups/$AKV_RG/providers/Microsoft.KeyVault/vaults/$AKV_NAME"
    

在 AKV 中分配访问策略(旧版)

标识需要以下权限:

  • Create 权限,用于创建证书
  • Get 权限,用于读取现有证书
  • Sign 权限,用于对操作进行签名

若要详细了解如何将策略分配给主体,请参阅分配访问策略

  1. 设置包含 AKV 资源的订阅:

    az account set --subscription $AKV_SUB_ID
    
  2. 在 AKV 中设置访问策略:

    USER_ID=$(az ad signed-in-user show --query id -o tsv)
    az keyvault set-policy -n $AKV_NAME --certificate-permissions create get --key-permissions sign --object-id $USER_ID
    

重要

此示例显示了创建证书和对容器映像进行签名所需的最低权限。 根据要求,可能需要授予其他权限。

在 AKV (Azure CLI) 中创建自签名证书

以下步骤演示如何为测试创建自签名证书。

  1. 创建证书策略文件。

    如下所示,执行证书策略文件后,它会创建与 AKV 中的 Notary Project 证书要求兼容的有效证书。 ekus 的值用于代码签名,但表示法不需要使用它即可对项目进行签名。 主题稍后用作用户在验证期间信任的信任标识。

    cat <<EOF > ./my_policy.json
    {
        "issuerParameters": {
        "certificateTransparency": null,
        "name": "Self"
        },
        "keyProperties": {
          "exportable": false,
          "keySize": 2048,
          "keyType": "RSA",
          "reuseKey": true
        },
        "secretProperties": {
          "contentType": "application/x-pem-file"
        },
        "x509CertificateProperties": {
        "ekus": [
            "1.3.6.1.5.5.7.3.3"
        ],
        "keyUsage": [
            "digitalSignature"
        ],
        "subject": "$CERT_SUBJECT",
        "validityInMonths": 12
        }
    }
    EOF
    
  2. 创建证书。

    az keyvault certificate create -n $CERT_NAME --vault-name $AKV_NAME -p @my_policy.json
    

使用 Notation CLI 和 AKV 插件为容器映像签名

  1. 使用单个 Azure 标识向 ACR 进行身份验证。

    az acr login --name $ACR_NAME
    

重要

如果已在系统上安装 Docker 并使用 az acr logindocker login 向 ACR 进行身份验证,则凭据已存储并可用于表示法。 在这种情况下,无需再次运行 notation login 即可向 ACR 进行身份验证。 若要详细了解表示法的身份验证选项,请参阅使用符合 OCI 的注册表进行身份验证

  1. 使用 Azure 任务生成并推送新映像。 始终使用摘要值来标识要签名的映像,因为标记是可变的,可以覆盖。

    DIGEST=$(az acr build -r $ACR_NAME -t $REGISTRY/${REPO}:$TAG $IMAGE_SOURCE --no-logs --query "outputImages[0].digest" -o tsv)
    IMAGE=$REGISTRY/${REPO}@$DIGEST
    

    在本教程中,如果映像已生成并存储在注册表中,为方便起见,标记将用作该映像的标识符。

    IMAGE=$REGISTRY/${REPO}:$TAG
    
  2. 获取签名密钥的密钥 ID。 AKV 中的证书可以有多个版本,以下命令获取最新版本的密钥 ID。

    KEY_ID=$(az keyvault certificate show -n $CERT_NAME --vault-name $AKV_NAME --query 'kid' -o tsv)
    
  3. 使用签名密钥,以 COSE 签名格式为容器映像签名。 若要使用自签名证书进行签名,需要设置插件配置值 self_signed=true

    notation sign --signature-format cose --id $KEY_ID --plugin azure-kv --plugin-config self_signed=true $IMAGE
    

    若要使用 AKV 进行身份验证,默认将按顺序尝试以下凭据类型(如果已启用):

    如果你要指定凭据类型,请使用名为 credential_type 的附加插件配置。 例如,可以将 credential_type 显式设置为 azurecli 以使用 Azure CLI 凭据,如下所示:

    notation sign --signature-format cose --id $KEY_ID --plugin azure-kv --plugin-config self_signed=true --plugin-config credential_type=azurecli $IMAGE
    

    请参阅下表了解各种凭据类型的 credential_type 值。

    凭据类型 credential_type 的值
    环境凭据 environment
    工作负载标识凭据 workloadid
    托管标识凭据 managedid
    Azure CLI 凭据 azurecli
  4. 查看已签名映像和关联签名的图。

    notation ls $IMAGE
    

使用 Notation CLI 为容器映像签名

若要验证容器映像,请将对叶证书进行签名的根证书添加到信任存储区,并创建用于验证的信任策略。 对于本教程中使用的自签名证书,根证书是自签名证书本身。

  1. 下载公共证书。

    az keyvault certificate download --name $CERT_NAME --vault-name $AKV_NAME --file $CERT_PATH
    
  2. 将下载的公共证书添加到命名信任存储,以便进行签名验证。

    STORE_TYPE="ca"
    STORE_NAME="wabbit-networks.io"
    notation cert add --type $STORE_TYPE --store $STORE_NAME $CERT_PATH
    
  3. 列出要确认的证书。

    notation cert ls
    
  4. 在验证之前先配置信任策略。

    信任策略允许用户指定经过微调的验证策略。 以下示例配置名为 wabbit-networks-images 的信任策略,该策略适用于 $REGISTRY/$REPO 中的所有项目,并使用 $STORE_TYPE 类型的具名信任存储 $STORE_NAME。 它还假定用户信任具有 X.509 主题 $CERT_SUBJECT 的特定标识。 有关详细信息,请参阅信任存储和信任策略规范

    cat <<EOF > ./trustpolicy.json
    {
        "version": "1.0",
        "trustPolicies": [
            {
                "name": "wabbit-networks-images",
                "registryScopes": [ "$REGISTRY/$REPO" ],
                "signatureVerification": {
                    "level" : "strict" 
                },
                "trustStores": [ "$STORE_TYPE:$STORE_NAME" ],
                "trustedIdentities": [
                    "x509.subject: $CERT_SUBJECT"
                ]
            }
        ]
    }
    EOF
    
  5. 使用 notation policy 从我们之前创建的 JSON 文件导入信任策略配置。

    notation policy import ./trustpolicy.json
    notation policy show
    
  6. 使用 notation verify 验证容器映像自生成时以来未发生更改。

    notation verify $IMAGE
    

    使用信任策略成功验证映像后,将在成功输出消息中返回已验证映像的 sha256 摘要。

时间戳

自 Notation v1.2.0 发布以来,Notation 支持符合 RFC 3161 的时间戳。 此增强功能通过信任时间戳颁发机构 (TSA) 来延长对证书有效期内创建的签名的信任,即使在证书过期后也能成功进行签名验证。 作为映像签名者,应确保使用受信任的 TSA 生成的时间戳对容器映像进行签名。 作为映像验证者,若要验证时间戳,应确保信任映像签名者和关联的 TSA,并通过信任存储和信任策略来建立信任。 时间戳消除了由于证书过期而定期重新签署映像的需要,从而降低了成本,这在使用短期证书时尤为重要。 有关如何使用时间戳进行签名和验证的详细说明,请参阅公证项目时间戳指南

后续步骤

Notation 还在 Azure 管道和 GitHub Actions 工作流上提供 CI/CD 解决方案:

验证 AKS 或 Kubernetes 中的已签名映像部署: