使用自签名证书通过表示法和 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 根据签名验证容器映像
- 时间戳
先决条件
- 创建或使用 Azure 容器注册表来存储容器映像和签名
- 创建或使用 Azure Key Vault 来管理证书
- 安装并配置最新的 Azure CLI。
安装 Notation CLI 和 AKV 插件
在 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
在 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
列出可用的插件,并确认版本为
1.2.0
的azure-kv
插件是否已包含在列表中。notation plugin ls
配置环境变量
注意
为便于执行教程中的命令,请提供 Azure 资源的值来匹配现有的 ACR 和 AKV 资源。
配置 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
配置 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 中为容器映像签名需要 AcrPull
和 AcrPush
角色。
设置包含 ACR 资源的订阅
az account set --subscription $ACR_SUB_ID
分配角色
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 访问权限的两个选项。
使用 Azure RBAC(建议)
使用自签名证书进行签名需要以下角色:
Key Vault Certificates Officer
,用于创建和读取证书Key Vault Certificates User
,用于读取现有证书Key Vault Crypto User
,用于对操作进行签名
若要了解有关使用 Azure RBAC 进行 Key Vault 访问的详细信息,请参阅使用 Azure RBAC 管理访问权限。
设置包含 AKV 资源的订阅
az account set --subscription $AKV_SUB_ID
分配角色
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
权限,用于对操作进行签名
若要详细了解如何将策略分配给主体,请参阅分配访问策略。
设置包含 AKV 资源的订阅:
az account set --subscription $AKV_SUB_ID
在 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) 中创建自签名证书
以下步骤演示如何为测试创建自签名证书。
创建证书策略文件。
如下所示,执行证书策略文件后,它会创建与 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
创建证书。
az keyvault certificate create -n $CERT_NAME --vault-name $AKV_NAME -p @my_policy.json
使用 Notation CLI 和 AKV 插件为容器映像签名
使用单个 Azure 标识向 ACR 进行身份验证。
az acr login --name $ACR_NAME
重要
如果已在系统上安装 Docker 并使用 az acr login
或 docker login
向 ACR 进行身份验证,则凭据已存储并可用于表示法。 在这种情况下,无需再次运行 notation login
即可向 ACR 进行身份验证。 若要详细了解表示法的身份验证选项,请参阅使用符合 OCI 的注册表进行身份验证。
使用 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
获取签名密钥的密钥 ID。 AKV 中的证书可以有多个版本,以下命令获取最新版本的密钥 ID。
KEY_ID=$(az keyvault certificate show -n $CERT_NAME --vault-name $AKV_NAME --query 'kid' -o tsv)
使用签名密钥,以 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
查看已签名映像和关联签名的图。
notation ls $IMAGE
使用 Notation CLI 为容器映像签名
若要验证容器映像,请将对叶证书进行签名的根证书添加到信任存储区,并创建用于验证的信任策略。 对于本教程中使用的自签名证书,根证书是自签名证书本身。
下载公共证书。
az keyvault certificate download --name $CERT_NAME --vault-name $AKV_NAME --file $CERT_PATH
将下载的公共证书添加到命名信任存储,以便进行签名验证。
STORE_TYPE="ca" STORE_NAME="wabbit-networks.io" notation cert add --type $STORE_TYPE --store $STORE_NAME $CERT_PATH
列出要确认的证书。
notation cert ls
在验证之前先配置信任策略。
信任策略允许用户指定经过微调的验证策略。 以下示例配置名为
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
使用
notation policy
从我们之前创建的 JSON 文件导入信任策略配置。notation policy import ./trustpolicy.json notation policy show
使用
notation verify
验证容器映像自生成时以来未发生更改。notation verify $IMAGE
使用信任策略成功验证映像后,将在成功输出消息中返回已验证映像的 sha256 摘要。
时间戳
自 Notation v1.2.0 发布以来,Notation 支持符合 RFC 3161 的时间戳。 此增强功能通过信任时间戳颁发机构 (TSA) 来延长对证书有效期内创建的签名的信任,即使在证书过期后也能成功进行签名验证。 作为映像签名者,应确保使用受信任的 TSA 生成的时间戳对容器映像进行签名。 作为映像验证者,若要验证时间戳,应确保信任映像签名者和关联的 TSA,并通过信任存储和信任策略来建立信任。 时间戳消除了由于证书过期而定期重新签署映像的需要,从而降低了成本,这在使用短期证书时尤为重要。 有关如何使用时间戳进行签名和验证的详细说明,请参阅公证项目时间戳指南。
后续步骤
Notation 还在 Azure 管道和 GitHub Actions 工作流上提供 CI/CD 解决方案:
验证 AKS 或 Kubernetes 中的已签名映像部署: