你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
本文是一系列关于确保容器映像和其他开放容器计划(OCI)项目的完整性和真实性的一部分。 对于完整情况,请从概述开始,该 概述解释了签名为何重要并概述了各种方案。
使用来自受信任的证书颁发机构(CA)的证书对容器映像进行签名和验证是一种有价值的安全做法。 它可帮助你负责识别、授权和验证容器映像的发布者和容器映像本身的标识。 GlobalSign、DigiCert 等受信任 CA 在以下方面发挥着关键作用:
- 验证用户或组织的标识。
- 维护数字证书的安全性。
- 如果出现任何风险或滥用,立即撤销证书。
下面是一些基本组件,可帮助你使用受信任的 CA 中的证书对容器映像进行签名和验证:
- 表示法 是由 公证项目社区 开发的开源供应链安全工具,由Microsoft提供支持。 它支持对容器映像和其他项目进行签名和验证。
- Azure Key Vault 是一种基于云的服务,用于管理加密密钥、机密和证书。 它可帮助你使用签名密钥安全地存储和管理证书。
-
密钥保管库插件 (
notation-azure-kv) 是 Notation 的扩展。 它使用 Key Vault 中存储的密钥对容器映像和项目的数字签名进行签名和验证。 - Azure 容器注册表是一个专用注册表,可用于将签名附加到容器映像,以及存储和管理这些映像。
验证映像时,签名用于验证映像的完整性和签名者的标识。 此验证有助于确保容器映像不会被篡改,并且来自受信任的源。
在这篇文章中,你将学会如何:
- 安装 Notation 命令行界面(CLI)和 Key Vault 插件。
- 在 Key Vault 中创建或导入 CA 颁发的证书。
- 使用容器注册表任务生成和推送容器映像。
- 使用 Notation CLI 和 Key Vault 插件对容器镜像进行签署。
- 使用 Notation CLI 验证容器镜像签名。
- 使用时间戳。
Prerequisites
- 创建或使用 容器注册表 来存储容器映像和签名。
- 创建或使用 密钥保管库。 建议创建一个新的密钥保管库,以便仅存储证书。
- 安装和配置最新的 Azure CLI 版本,或在 Azure Cloud Shell 中运行命令。
安装 Notation CLI 和 Key Vault 插件
在 Linux AMD64 环境中安装 Notation v1.3.2。 若要下载适用于其他环境的包,请按照 符号安装指南进行安装。
# Download, extract, and install curl -Lo notation.tar.gz https://github.com/notaryproject/notation/releases/download/v1.3.2/notation_1.3.2_linux_amd64.tar.gz tar xvzf notation.tar.gz # Copy the Notation CLI to the desired bin directory in PATH, for example cp ./notation /usr/local/bin在 Linux AMD64 环境中安装 Key Vault 插件 (
notation-azure-kv) v1.2.1。注意
可以在插件的发布页面找到插件的 URL 和 SHA256 校验和。
notation plugin install --url https://github.com/Azure/notation-azure-kv/releases/download/v1.2.1/notation-azure-kv_1.2.1_linux_amd64.tar.gz --sha256sum 67c5ccaaf28dd44d2b6572684d84e344a02c2258af1d65ead3910b3156d3eaf5列出可用的插件,并确认
notation-azure-kv列表中是否包含带有版本的1.2.1插件:notation plugin ls
配置环境变量
本文使用环境变量来方便配置 Key Vault 和容器注册表。 更新特定资源的这些环境变量的值。
为 Key Vault 和证书配置环境变量:
AKV_SUB_ID=myAkvSubscriptionId AKV_RG=myAkvResourceGroup AKV_NAME=myakv # Name of the certificate created or imported in Key Vault CERT_NAME=wabbit-networks-io # X.509 certificate subject CERT_SUBJECT="CN=wabbit-networks.io,O=Notation,L=Seattle,ST=WA,C=US"为容器注册表和映像配置环境变量:
ACR_SUB_ID=myAcrSubscriptionId ACR_RG=myAcrResourceGroup # Name of the existing registry example: myregistry.azurecr.io ACR_NAME=myregistry # Existing full domain of the container registry REGISTRY=$ACR_NAME.azurecr.io # Container name inside the container registry where the image will be stored REPO=net-monitor TAG=v1 # Source code directory that contains the Dockerfile to build IMAGE_SOURCE=https://github.com/wabbit-networks/net-monitor.git#main
使用 Azure CLI 登录
az login
有关详细信息,请参阅 使用 Azure CLI 向 Azure 进行身份验证。
在 Key Vault 中创建或导入 CA 颁发的证书
了解证书要求
创建用于签名和验证的证书时,证书必须满足 公证项目证书要求。
以下是根证书和中间证书的要求:
- 扩展
basicConstraints必须存在并标记为critical。 字段CA必须设置为true。 - 扩展
keyUsage必须存在并标记为critical。 必须设置keyCertSign的位位置。
下面是 CA 颁发证书的要求:
- X.509 证书属性:
- 主题必须包含公用名(
CN)、国家/地区(C)、州或省(ST)和组织(O)。 本文使用$CERT_SUBJECT作为主题。 - X.509 密钥用法标记必须仅为
DigitalSignature。 - 扩展密钥用法(EKUs)必须为空或
1.3.6.1.5.5.7.3.3(用于代码签名)。
- 主题必须包含公用名(
- 密钥属性:
-
exportable属性必须设置为false。 - 从 Notary 项目规范选择支持的密钥类型和大小。
-
重要说明
为了确保与映像完整性成功集成,证书的内容类型应设置为 PEM。
本指南使用 Key Vault 插件版本 1.0.1。 早期版本的插件有一个限制,要求证书链中的特定证书顺序。 插件版本 1.0.1 没有此限制,因此建议使用版本 1.0.1 或更高版本。
创建 CA 颁发的证书
按照 Key Vault 中创建和合并证书签名请求中的说明创建证书签名请求(CSR)。
合并 CSR 时,请确保合并从 CA 供应商返回的整个证书链。
在 Key Vault 中导入证书
若要导入证书,请执行以下操作:
- 使用整个证书链从 CA 供应商获取证书文件。
- 按照 在 Azure Key Vault 中导入证书的说明将证书导入 Key Vault。
如果在创建或导入证书后,证书不包含证书链,可以从您的证书颁发机构供应商获取中间证书和根证书。 可以要求供应商提供包含中间证书(如果有)和根证书的 PEM 文件。 然后,在对容器映像进行签名时,可以使用此文件。
使用 Notation CLI 和 Key Vault 插件对容器镜像进行签名
使用容器注册表和 Key Vault 时,必须授予适当的权限,以帮助确保安全和控制的访问。 可以根据特定方案为各种实体(例如用户主体、服务主体或托管标识)授予访问权限。 在本文中,已登录的 Azure 用户已授权访问。
授权访问容器注册表
对于启用了 Microsoft Entra 属性访问控制 (ABAC) 的注册表,在容器注册表中生成和签署容器映像需要 Container Registry Repository Reader 和 Container Registry Repository Writer 角色。
对于未启用 ABAC 的注册表,需要 AcrPull 和 AcrPush 角色。
有关 ABAC 的详细信息,请参阅 Microsoft Entra 基于属性的存储库权限访问控制。
设置包含容器注册表资源的订阅:
az account set --subscription $ACR_SUB_ID分配角色:
USER_ID=$(az ad signed-in-user show --query id -o tsv) ROLE1="Container Registry Repository Reader" # For ABAC-enabled registries. Otherwise, use "AcrPull" for non-ABAC-enabled registries. ROLE2="Container Registry Repository Writer" # For ABAC-enabled registries. Otherwise, use "AcrPush" for non-ABAC-enabled registries. az role assignment create --role "$ROLE1" --role "$ROLE2" --assignee $USER_ID --scope "/subscriptions/$ACR_SUB_ID/resourceGroups/$ACR_RG/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME"
生成容器映像并将其推送到容器注册表
使用单个 Azure 标识向容器注册表进行身份验证:
az acr login --name $ACR_NAME重要说明
如果在系统上安装了 Docker,并且使用
az acr login或docker login对容器注册表进行了身份验证,则您的凭据已存储并可供 Notation 使用。 在这种情况下,无需再次运行notation login,才能向容器注册表进行身份验证。 若要详细了解 Notation 的身份验证选项,请参阅 在符合 OCI 的注册表中进行身份验证。使用容器注册表任务生成和推送新映像。 始终使用
digest来标识签名图像,因为标签是可变的并且可以被覆盖。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
授权访问“Key Vault”
本部分探讨两个选项,用于授权访问 Key Vault。
使用 Azure RBAC(建议)
设置包含 Key Vault 资源的订阅:
az account set --subscription $AKV_SUB_ID分配角色。
如果证书包含整个证书链,则必须使用以下角色分配主体:
-
Key Vault Secrets User(用于读取机密) -
Key Vault Certificates User用于读取证书 -
Key Vault Crypto User用于签名操作
USER_ID=$(az ad signed-in-user show --query id -o tsv) az role assignment create --role "Key Vault Secrets User" --role "Key Vault Certificates User" --role "Key Vault Crypto User" --assignee $USER_ID --scope "/subscriptions/$AKV_SUB_ID/resourceGroups/$AKV_RG/providers/Microsoft.KeyVault/vaults/$AKV_NAME"如果证书不包含证书链,则必须为主体分配以下角色:
-
Key Vault Certificates User用于读取证书 -
Key Vault Crypto User用于签名操作
USER_ID=$(az ad signed-in-user show --query id -o tsv) az role assignment create --role "Key Vault Certificates User" --role "Key Vault Crypto User" --assignee $USER_ID --scope "/subscriptions/$AKV_SUB_ID/resourceGroups/$AKV_RG/providers/Microsoft.KeyVault/vaults/$AKV_NAME"-
若要详细了解使用 Azure 基于角色的访问控制(RBAC)进行 Key Vault 访问,请参阅 使用 Azure 基于角色的访问控制提供对 Key Vault 密钥、证书和机密的访问权限。
使用访问策略(旧版)
若要设置包含 Key Vault 资源的订阅,请运行以下命令:
az account set --subscription $AKV_SUB_ID
如果证书包含整个证书链,则必须向主体授予密钥权限 Sign、机密权限 Get和证书权限 Get。 若要向主体授予这些权限,请使用以下命令:
USER_ID=$(az ad signed-in-user show --query id -o tsv)
az keyvault set-policy -n $AKV_NAME --key-permissions sign --secret-permissions get --certificate-permissions get --object-id $USER_ID
如果证书不包含链,则必须向主体授予密钥权限 Sign 和证书权限 Get。 若要向主体授予这些权限,请使用以下命令:
USER_ID=$(az ad signed-in-user show --query id -o tsv)
az keyvault set-policy -n $AKV_NAME --key-permissions sign --certificate-permissions get --object-id $USER_ID
若要详细了解如何将策略分配给主体,请参阅“分配 Key Vault 访问策略”(旧版)。
使用 Key Vault 中的证书对容器映像进行签名
获取证书的密钥 ID。 Key Vault 中的证书可以有多个版本。 以下命令获取最新版本证书的
$CERT_NAME密钥 ID:KEY_ID=$(az keyvault certificate show -n $CERT_NAME --vault-name $AKV_NAME --query 'kid' -o tsv)使用密钥 ID,以 CBOR 对象签名和加密(COSE)签名格式对容器映像进行签名。
如果证书包含整个证书链,请运行以下命令:
notation sign --signature-format cose $IMAGE --id $KEY_ID --plugin azure-kv如果证书不包含链,请使用
--plugin-config ca_certs=<ca_bundle_file>参数将 PEM 文件中的 CA 证书传递给 Key Vault 插件。 运行下面的命令:notation sign --signature-format cose $IMAGE --id $KEY_ID --plugin azure-kv --plugin-config ca_certs=<ca_bundle_file>若要使用 Key Vault 进行身份验证,默认情况下,会按顺序尝试以下凭据类型(如果已启用):
如果要指定凭据类型,请使用名为
credential_type的其他插件配置。 例如,可以显式地将credential_type设置为azurecli以使用 Azure CLI 凭据,如以下示例所示:notation sign --signature-format cose --id $KEY_ID --plugin azure-kv --plugin-config credential_type=azurecli $IMAGE下表显示了各种凭据类型的
credential_type值。凭据类型 credential_type的值环境凭据 environment工作负载标识凭据 workloadid托管标识凭据 managedidAzure CLI 凭据 azurecli查看已签名图像及其关联签名的图表。
notation ls $IMAGE在以下输出示例中,摘要
application/vnd.cncf.notary.signature标识的类型sha256:d7258166ca820f5ab7190247663464f2dcb149df4d1b6c4943dcaac59157de8e的签名与$IMAGE相关联:myregistry.azurecr.io/net-monitor@sha256:17cc5dd7dfb8739e19e33e43680e43071f07497ed716814f3ac80bd4aac1b58f └── application/vnd.cncf.notary.signature └── sha256:d7258166ca820f5ab7190247663464f2dcb149df4d1b6c4943dcaac59157de8e
注意
由于表示法 v1.2.0,表示法默认使用 OCI 引用器标记架构 将签名存储在容器注册表中。 如有必要,还可以使用标志启用 --force-referrers-tag false。 容器注册表功能支持 OCI 引荐者 API,但使用客户管理的密钥 (CMK) 加密的注册表除外。
使用 Notation CLI 验证容器镜像
将根证书添加到命名信任存储,以便进行签名验证。 如果没有根证书,可以从 CA 获取它。 以下示例将根证书
$ROOT_CERT添加到$STORE_NAME信任存储:STORE_TYPE="ca" STORE_NAME="wabbit-networks.io" notation cert add --type $STORE_TYPE --store $STORE_NAME $ROOT_CERT列出根证书,确认
$ROOT_CERT已成功添加:notation cert ls在验证之前配置信任策略。 信任策略使用户能够指定微调的验证策略。 使用以下命令:
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上述
文件定义了一个名为 的信任策略。 此信任策略适用于 $REGISTRY/$REPO存储库中存储的所有项目。$STORE_NAME类型的命名信任存储$STORE_TYPE包含根证书。 此策略还假定用户信任一个特定标识,该标识具有 X.509 主题$CERT_SUBJECT。 有关详细信息,请参阅 信任存储和信任策略规范。使用
notation policy从trustpolicy.json导入信任策略配置:notation policy import ./trustpolicy.json显示信任策略配置以确认其成功导入:
notation policy show使用
notation verify验证映像的完整性:notation verify $IMAGE通过信任策略成功验证映像后,验证图像的 SHA256 摘要会在成功的输出消息中返回。 下面是输出示例:
Successfully verified signature for myregistry.azurecr.io/net-monitor@sha256:17cc5dd7dfb8739e19e33e43680e43071f07497ed716814f3ac80bd4aac1b58f
使用时间戳
自 Notation v1.2.0 版本以来,Notation 支持符合 RFC 3161 的时间戳。 此项增强通过信任时间戳颁发机构 (TSA),扩展了在证书有效期内创建的签名的信任范围。 即使证书过期,此信任也能成功进行签名验证。
作为映像签名者,应确保使用受信任的 TSA 生成的时间戳对容器映像进行签名。 映像验证者应确保信任映像签名者和关联的 TSA,并通过信任存储和信任策略来建立信任。
时间戳消除了由于证书过期而定期重新签署映像的需要,从而降低了成本。 使用生存期较短的证书时,此功能尤其重要。 有关如何使用时间戳对图像进行签名和验证的详细说明,请参阅 公证项目时间戳指南。
FAQ
如果证书过期,该怎么办?
如果证书过期,则需要从受信任的 CA 供应商获取新证书以及新的私钥。 无法使用过期的证书对容器映像进行签名。
如果已使用 时间戳签名,则证书过期前签名的映像仍可以成功验证。 如果没有时间戳,签名验证将失败,并且需要使用新证书重新为这些映像签名才能成功验证。
如果证书已吊销,该怎么办?
吊销证书会使签名失效。 这种情况可能会由于多种原因而发生,例如私钥泄露或更改证书持有者的附属关系。
若要解决此问题,应首先确保源代码和生成环境是最新的且安全的。 然后,从源代码生成容器映像、从受信任的 CA 供应商获取新证书以及新的私钥,并按照本指南使用新证书对新容器映像进行签名。
相关内容
Notation 在 Azure Pipelines 和 GitHub Actions 上提供持续集成和持续交付(CI/CD)解决方案。
- 若要在 Azure DevOps 管道中对容器映像进行签名和验证,请参阅 在 Azure 管道中使用表示法对容器映像进行签名和验证。
- 若要使用 GitHub Actions 对容器映像进行签名,请参阅 在 GitHub Actions 中使用表示法对容器映像进行签名。
- 若要使用 GitHub Actions 验证容器映像,请参阅使用 GitHub Actions 中的表示法验证容器映像。
为了确保仅在 Azure Kubernetes 服务(AKS)上部署受信任的容器映像:
- 使用 Azure Policy 映像完整性(预览版),按照指南使用映像完整性功能在将签名的映像部署到 Azure Kubernetes 服务群集(预览版)之前进行验证。
- 使用Ratify和 Azure Policy,按照指南使用 Ratify 和 Azure Policy 验证容器映像签名进行操作。