容器安全性在云原生环境中至关重要,用于保护工作负荷。 为了改善安全态势,Azure 引入了 容器安全供应链(CSSC)框架,增强了容器映像整个生命周期的安全性。 CSSC 框架中定义的阶段之一是 Deploy
阶段,即在其中容器映像被部署到生产环境,例如 Azure Kubernetes 服务(AKS)群集。 确保安全生产环境涉及维护容器映像的完整性和真实性,这是通过在生成阶段对容器映像进行签名来实现的,然后在部署阶段验证它们,确保仅部署受信任的和未更改的映像。
Ratify 是由 Microsoft 支持的 CNCF 沙盒项目,是一个强大的验证引擎,专注于验证容器镜像的安全元数据,如签名,并仅允许部署符合您指定策略的镜像。
Scenarios
本部分介绍在 AKS 上实现容器映像签名验证的两个主要方案。 这些方案因管理证书进行签名和验证的方式而异:使用 Azure Key Vault (AKV) 进行传统证书管理。 选择符合当前证书管理方法和安全要求的方案。
使用 AKV 进行证书管理
映像生成者在 CI/CD 管道中生成容器映像并将其推送到 Azure 容器注册表(ACR)。 这些映像适用于映像使用者在 AKS 群集上部署和运行云原生工作负荷。 映像生成者在 CI/CD 管道中使用 Notary Project 工具(特别是 Notation)在 ACR 中对容器映像进行签名。 用于签名的密钥和证书安全地存储在 Azure Key Vault (AKV) 中。 签名完成后,公证项目签名将被创建并存储在 ACR 中,并引用相应的图像。 映像使用者在 AKS 群集上设置批准策略,以在部署期间验证映像的公证项目签名。 如果策略效果设置为拒绝效果,则签名验证失败的映像将无法部署。 这可确保仅将受信任的和未更改的映像部署到 AKS 群集。
作为映像生成者,请按照以下文档使用 AKV 在 ACR 中对容器映像进行签名:
有关使用自签名证书进行签名的信息,请参阅 使用 Notation CLI 和 AKV 通过自签名证书对容器映像进行签名
关于使用 CA 颁发的证书进行签名,请参阅 使用 Notation CLI 和 AKV 对容器映像进行签名。
若要登录 Azure DevOps (ADO) 管道,请参阅 在 Azure DevOps (ADO) 管道中对容器映像进行签名
若要登录 GitHub 工作流,请参阅 在 GitHub 工作流中为容器映像签名
签名验证概述
下面是签名验证的高级步骤:
为 ACR 设置标识和访问控制:配置 Ratify 使用的标识,以必要的角色访问 ACR。
为 AKV 设置标识和访问控制:配置 Ratify 使用的标识,以访问 AKV,并授予其必要的角色。 如果图像使用受信任的签名,请跳过此步骤。
在 AKS 群集上设置 Ratify:使用 Helm Chart 安装,将 Ratify 设置为标准的 Kubernetes 服务。
设置自定义 Azure 策略:创建并分配具有所需策略效果的自定义 Azure 策略:
Deny
或Audit
。
执行这些步骤后,可以开始部署工作负载来观察结果。
Deny
使用效果策略时,仅允许通过签名验证的映像进行部署,而未签名或由不受信任的标识签名的映像将被拒绝。
Audit
借助效果策略,可以部署映像,但组件将标记为不符合审核目的。
先决条件
安装和配置最新的 Azure CLI。
请按照 使用 OpenID Connect (OIDC) 颁发者配置 AKS 群集中的步骤,创建或使用启用了 OIDC 颁发者的 AKS 群集。 此 AKS 群集将是你的容器映像部署的位置,Ratify 将被安装,自定义 Azure 策略将被应用。
如果尚未通过 AKS 中的 ACR 进行身份验证步骤,将 ACR 连接到 AKS 群集。 ACR 是容器映像的存储位置,用于部署到 AKS 群集。
启用 Azure Policy 加载项。 若要验证是否已安装加载项,或者要安装它(如果尚未安装),请按照 适用于 AKS 的 Azure Policy 加载项中的步骤进行作。
设置标识和访问控制
在 AKS 群集上安装批准之前,需要建立适当的标识和访问控制。 Ratify 需要访问 ACR 来拉取容器映像和签名,并且在使用 Azure Key Vault 进行证书管理时,也需要访问以获取证书用于签名验证。 本部分将指导你创建用户分配的托管标识,并配置批准所需的权限,以便在 Azure 环境中安全运行。
标识配置涉及:
- 创建或使用现有用户分配的托管标识
- 设置联合身份凭证以启用工作负载身份验证
- 为 ACR 访问权限授予适当的角色分配
- 配置 AKV 访问权限(使用 AKV 进行证书管理时)
创建或使用用户分配的托管标识
如果还没有用户分配的托管标识,请按照 本文档 创建一个。 Ratify 将使用此标识来访问 Azure 资源,比如 ACR,并在适用时使用 AKV 进行证书管理。
为您的身份创建联合身份凭据
设置环境变量:
export AKS_RG=<aks-resource-group-name>
export AKS_NAME=<aks-name>
export AKS_OIDC_ISSUER=$(az aks show -n $AKS_NAME -g $AKS_RG --query "oidcIssuerProfile.issuerUrl" -otsv)
export IDENTITY_RG=<identity-resource-group-name>
export IDENTITY_NAME=<identity-name>
export IDENTITY_CLIENT_ID=$(az identity show --name $IDENTITY_NAME --resource-group $IDENTITY_RG --query 'clientId' -o tsv)
export IDENTITY_OBJECT_ID=$(az identity show --name $IDENTITY_NAME --resource-group $IDENTITY_RG --query 'principalId' -otsv)
export RATIFY_NAMESPACE="gatekeeper-system"
export RATIFY_SA_NAME="ratify-admin"
注释
如果不使用默认值,请更新变量 RATIFY_NAMESPACE
和 RATIFY_SA_NAME
的值。 务必在安装 Ratify Helm 图表时使用相同的值。
以下命令为托管标识创建一个联合凭据,允许它使用由 OIDC 发行者颁发的令牌进行身份验证,特别是针对命名空间RATIFY_NAMESPACE
中的 Kubernetes 服务帐户RATIFY_SA_NAME
。
az identity federated-credential create \
--name ratify-federated-credential \
--identity-name "$IDENTITY_NAME" \
--resource-group "$IDENTITY_RG" \
--issuer "$AKS_OIDC_ISSUER" \
--subject system:serviceaccount:"$RATIFY_NAMESPACE":"$RATIFY_SA_NAME"
配置对 ACR 的访问权限
要拉取签名和其他容器映像元数据,您的标识需要具有角色 AcrPull
。 使用以下指示分配角色:
export ACR_SUB=<acr-subscription-id>
export ACR_RG=<acr-resource-group>
export ACR_NAME=<acr-name>
az role assignment create \
--role acrpull \
--assignee-object-id ${IDENTITY_OBJECT_ID} \
--scope subscriptions/${ACR_SUB}/resourceGroups/${ACR_RG}/providers/Microsoft.ContainerRegistry/registries/${ACR_NAME}
配置对 AKV 的访问
如果使用受信任的签名进行证书管理,请跳过此步骤。
您的标识需要 Key Vault Secrets User
角色才能从 Azure 密钥保管库 (AKV) 获取整个证书链。 请按照以下说明来分配角色:
为 AKV 资源设置额外的环境变量:
export AKV_SUB=<acr-subscription-id>
export AKV_RG=<acr-resource-group>
export AKV_NAME=<acr-name>
az role assignment create \
--role "Key Vault Secrets User" \
--assignee ${IDENTITY_OBJECT_ID} \
--scope "/subscriptions/${AKV_SUB}/resourceGroups/${AKV_RG}/providers/Microsoft.KeyVault/vaults/${AKV_NAME}"
在启用了 Azure Policy 的 AKS 集群上部署 Ratify
正确配置身份和访问控制后,现在可以在 AKS 群集上安装 Ratify。 批准作为与 Azure Policy 集成的验证引擎运行,以强制实施签名验证策略。 安装过程涉及使用 Helm chart 部署 Ratify,其中包含特定配置参数,用于定义其应如何验证容器镜像签名。
本部分介绍批准设置的两个关键方面:
了解证书管理方法所需的 Helm 图表参数(AKV 签名)
使用适当的配置安装Ratify以启用签名验证功能
配置参数因是否使用 AKV 进行证书管理而有所不同,因此请确保按照与所选方案匹配的说明进行作。
了解 Helm 图表的参数
安装Ratify的Helm图表时,需要使用--set
标志或提供自定义值文件将值传递给参数。 这些值将用于配置Ratify以进行签名验证。 有关参数的综合列表,请参阅Ratify Helm 图表文档。
配置因是否使用 AKV 进行证书管理而有所不同。
您需要进行配置:
- 以前为访问 ACR 和 AKV 而设置的标识。
- 存储在 AKV 中用于签名验证的证书。
- 用于签名验证的公证项目信任策略,包括
registryScopes
、trustStores
和trustedIdentities
。
有关详细信息,请参阅下面的参数表:
参数 | Description | 价值 |
---|---|---|
azureWorkloadIdentity.clientId | 指定 Azure 工作负荷标识的客户端 ID | “$IDENTITY_CLIENT_ID” |
oras.authProviders.azureWorkloadIdentityEnabled | 为 ACR 身份验证启用/禁用 Azure 工作负荷标识 | 是 |
azurekeyvault.enabled | 启用/禁用从 AKV 获取证书 | 是 |
azurekeyvault.vaultURI | AKV 资源的 URI | “https://$AKV_NAME.vault.azure.cn” |
azurekeyvault.tenantId | AKV 资源的租户 ID | “$AKV_TENANT_ID” |
azurekeyvault.certificates[0].name | 证书的名称 | “$CERT_NAME” |
notation.trustPolicies[0].registryScopes[0] | 策略应用到的存储库 URI | “$REPO_URI” |
notation.trustPolicies[0].trustStores[0] | 信任存储用于存放类型为ca 或tsa 的证书 |
ca:azurekeyvault |
notation.trustPolicies[0].trustedIdentities[0] | 签名证书的主题字段包含前缀 x509.subject: ,用于指示您信任的对象。 |
“x509.subject: $SUBJECT” |
通过对图像进行时间戳记,可以确保在证书过期前签名的图像仍然可以成功验证。 为 TSA 配置添加以下参数:
参数 | Description | 价值 |
---|---|---|
notationCerts[0] | PEM 格式的 TSA 根证书文件的文件路径 | “$TSA_ROOT_CERT_FILEPATH” |
notation.trustPolicies[0].trustStores[1] | 存储 TSA 根证书的另一个信任存储区 | tsa:notationCerts[0] |
如果有多个证书用于签名验证,请指定额外的参数:
参数 | Description | 价值 |
---|---|---|
azurekeyvault.certificates[1].name | 证书的名称 | “$CERT_NAME_2” |
notation.trustPolicies[0].trustedIdentities[1] | 签名证书的另一个主题字段,表明您信任的对象 | x509.subject: $SUBJECT_2 |
安装 Ratify Helm 图表,并设定所需的参数和值。
确保 Ratify Helm 图表的版本至少为 1.15.0
,这将安装 Ratify 版本 1.4.0
或更高版本。 在此示例中,使用 helm 图表版本 1.15.0
。
设置用于安装的其他环境变量:
export CHART_VER="1.15.0"
export REPO_URI="$ACR_NAME.azurecr.cn/<namespace>/<repo>"
export SUBJECT="<Subject-of-signing-certificate>"
export AKV_TENANT_ID="$(az account show --query tenantId --output tsv)"
helm repo add ratify https://notaryproject.github.io/ratify
helm repo update
helm install ratify ratify/ratify --atomic --namespace $RATIFY_NAMESPACE --create-namespace --version $CHART_VER --set provider.enableMutation=false --set featureFlags.RATIFY_CERT_ROTATION=true \
--set azureWorkloadIdentity.clientId=$IDENTITY_CLIENT_ID \
--set oras.authProviders.azureWorkloadIdentityEnabled=true \
--set azurekeyvault.enabled=true \
--set azurekeyvault.vaultURI="https://$AKV_NAME.vault.azure.cn" \
--set azurekeyvault.certificates[0].name="$CERT_NAME" \
--set azurekeyvault.tenantId="$AKV_TENANT_ID" \
--set notation.trustPolicies[0].registryScopes[0]="$REPO_URI" \
--set notation.trustPolicies[0].trustStores[0]="ca:azurekeyvault" \
--set notation.trustPolicies[0].trustedIdentities[0]="x509.subject: $SUBJECT"
注释
对于时间戳支持,需要指定其他参数: --set-file notationCerts[0]="$TSA_ROOT_CERT_FILE"
和 --set notation.trustPolicies[0].trustStores[1]="ca:azurekeyvault"
。
重要
对于未链接到信任策略框架的映像,签名验证将失败。 例如,如果映像不在存储库 $REPO_URI
中,则这些映像的签名验证将失败。 可以通过指定其他参数来添加多个存储库。 例如,若要为信任策略 notation.trustPolicies[0]
添加另一个存储库,请包含参数 --set notation.trustPolicies[0].registryScopes[1]="$REPO_URI_1"
。
设置自定义 Azure 策略
在 AKS 群集上成功安装和配置批准后,最后一步是创建和分配一个 Azure Policy,该策略将在容器部署期间强制实施签名验证。 此策略充当强制机制,指示群集在允许部署之前使用批准来验证容器映像签名。
Azure Policy 提供两种强制模式:
- 拒绝效果:阻止部署未通过签名验证的映像,确保仅在群集中运行受信任的映像
- 审核效果:允许所有部署,但出于监视和报告目的标记合规资源
审核效果在初始设置或测试阶段非常有用,使你可以验证配置,而不会危及生产环境中的服务中断。
将新策略分配给 AKS 群集
创建自定义 Azure 策略进行签名验证。 默认情况下,策略效果设置为 Deny
,这意味着失败签名验证的映像被拒绝部署。 或者,您可以将策略效果配置为 Audit
,允许即使签名验证失败的映像也可以被部署,同时仍将 AKS 群集和相关工作负载标记为合规。
Audit
效果在验证签名验证配置时非常实用,可以避免因生产环境设置不当而造成的中断。
export CUSTOM_POLICY=$(curl -L https://raw.githubusercontent.com/notaryproject/ratify/refs/tags/v1.4.0/library/default/customazurepolicy.json)
export DEFINITION_NAME="ratify-default-custom-policy"
export DEFINITION_ID=$(az policy definition create --name "$DEFINITION_NAME" --rules "$(echo "$CUSTOM_POLICY" | jq .policyRule)" --params "$(echo "$CUSTOM_POLICY" | jq .parameters)" --mode "Microsoft.Kubernetes.Data" --query id -o tsv)
使用默认效果 Deny
将策略分配给 AKS 群集。
export POLICY_SCOPE=$(az aks show -g "$AKS_RG" -n "$AKS_NAME" --query id -o tsv)
az policy assignment create --policy "$DEFINITION_ID" --name "$DEFINITION_NAME" --scope "$POLICY_SCOPE"
若要将策略效果 Audit
更改为,可以将另一个参数传递给 az policy assignment create
命令。 例如:
az policy assignment create --policy "$DEFINITION_ID" --name "$DEFINITION_NAME" --scope "$POLICY_SCOPE" -p "{\"effect\": {\"value\":\"Audit\"}}"
注释
完成作业大约需要 15 分钟。
使用以下命令检查自定义策略状态。
kubectl get constraintTemplate ratifyverification
下面是成功策略分配的输出示例:
NAME AGE
ratifyverification 11m
若要对现有分配进行更改,首先需要删除现有分配,进行更改,最后创建新的分配。
部署映像并检查策略效果
现已成功配置“批准”并将 Azure Policy 分配到 AKS 群集,接下来可以测试签名验证功能。 本部分演示了如何通过部署不同类型的容器映像和观察结果来实施策略。
测试三种方案来验证设置:
- 使用受信任证书签名的映像:应成功部署
- 未签名图像:应阻止(具有拒绝效果)或标记为合规(具有审核效果)
- 使用不受信任的证书签名的图像:应阻止(具有拒绝效果)或标记为合规(具有审核效果)
观察到的行为取决于在 Azure Policy 分配步骤中选择的策略效果。 此测试过程有助于确保签名验证正常运行,并确保在生产环境中仅允许受信任的镜像,从而提高您对该过程的信心。
使用拒绝策略效果
通过 Deny
策略效果,仅允许使用受信任标识签名的映像进行部署。 可以开始部署工作负荷来观察效果。 本文档使用 kubectl
命令部署 Pod。 同样,可以使用 Helm 图表或任何触发 Helm 安装的模板部署工作负荷。
设置环境变量:
export IMAGE_SIGNED=<signed-image-reference>
export IMAGE_UNSIGNED=<unsigned-image-reference>
export IMAGE_SIGNED_UNTRUSTED=<signed-untrusted-image-reference>
运行以下命令。 由于$IMAGE_SIGNED
引用了由受信任的标识签名并在Ratify中配置的映像,因此允许其部署。
kubectl run demo-signed --image=$IMAGE_SIGNED
下面是成功部署的输出示例:
pod/demo-signed created
$IMAGE_UNSIGNED
引用未签名的图像。
$IMAGE_SIGNED_UNTRUSTED
引用一个使用您不信任的不同证书签名的映像。 因此,这两个镜像被拒绝部署。 例如,运行以下命令:
kubectl run demo-unsigned --image=$IMAGE_UNSIGNED
下面是一个被拒绝的部署输出示例:
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [azurepolicy-ratifyverification-077bac5b63d37da0bc4a] Subject failed verification: $IMAGE_UNSIGNED
可以使用以下命令输出批准日志并用文本 verification response for subject $IMAGE_UNSIGNED
搜索日志,检查 errorReason
字段以了解任何被拒绝部署的原因。
kubectl logs <ratify-pod> -n $RATIFY_NAMESPACE
使用审核策略的影响
在审核策略生效的情况下,允许部署未签名的映像或使用不受信任标识签名的映像。 但是,AKS 群集和相关组件被标记为 noncompliant
。 有关如何查看不符合资源并了解原因的更多详细信息,请参阅 “获取 Azure 策略符合性数据”。
清理
使用以下命令卸载 Ratify 并清理 Ratify CRD:
helm delete ratify --namespace $RATIFY_NAMESPACE
kubectl delete crd stores.config.ratify.deislabs.io verifiers.config.ratify.deislabs.io certificatestores.config.ratify.deislabs.io policies.config.ratify.deislabs.io keymanagementproviders.config.ratify.deislabs.io namespacedkeymanagementproviders.config.ratify.deislabs.io namespacedpolicies.config.ratify.deislabs.io namespacedstores.config.ratify.deislabs.io namespacedverifiers.config.ratify.deislabs.io
使用以下命令删除策略分配和定义:
az policy assignment delete --name "$DEFINITION_NAME" --scope "$POLICY_SCOPE"
az policy definition delete --name "$DEFINITION_NAME"
FAQ
如果我无权访问 AKV,如何设置用于签名验证的证书?
在某些情况下,映像使用者可能无权访问用于签名验证的证书。 若要验证签名,需要下载 PEM 格式的根 CA 证书文件,并为 Ratify Helm chart 安装指定相关参数。 下面是类似于上一个安装命令的示例命令,但没有任何与 AKV 证书相关的参数。 公证项目中的信任存储指的是作为参数传入的notationCerts[0]
证书文件:
helm install ratify ratify/ratify --atomic --namespace $RATIFY_NAMESPACE --create-namespace --version $CHART_VER --set provider.enableMutation=false --set featureFlags.RATIFY_CERT_ROTATION=true \
--set azureWorkloadIdentity.clientId=$IDENTITY_CLIENT_ID \
--set oras.authProviders.azureWorkloadIdentityEnabled=true \
--set-file notationCerts[0]="<root-ca-certifice-filepath>"
--set notation.trustPolicies[0].registryScopes[0]="$REPO_URI" \
--set notation.trustPolicies[0].trustStores[0]="ca:notationCerts[0]" \
--set notation.trustPolicies[0].trustedIdentities[0]="x509.subject: $SUBJECT"
注释
由于 notationCerts[0]
用于根 CA 证书,因此,如果有额外的证书文件用于时间戳,请确保使用正确的索引。 例如,notationCerts[1]
用于 TSA 根证书文件,然后使用具有值notation.trustPolicies[0].trustStores[1]"
的另一个信任存储"tsa:notationCerts[1]"
。
如果在 AKS 群集中禁用 Azure Policy,应采取哪些步骤?
如果在 AKS 群集上禁用 Azure Policy,则必须在安装批准之前将 OPA Gatekeeper 安装为策略控制器。
注释
Azure Policy 应保持禁用状态,因为 Gatekeeper 与 AKS 群集上的 Azure Policy 加载项冲突。 若要稍后启用 Azure Policy,则需要先卸载 Gatekeeper 和 Ratify,然后按照本文件的说明来设置启用 Azure Policy 的 Ratify。
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper \
--name-template=gatekeeper \
--namespace gatekeeper-system --create-namespace \
--set enableExternalData=true \
--set validatingWebhookTimeoutSeconds=5 \
--set mutatingWebhookTimeoutSeconds=2 \
--set externaldataProviderResponseCacheTTL=10s
然后,按照前面的步骤中所述安装Ratify。 安装后,使用以下命令强制实施策略。 默认情况下,策略效果设置为 Deny
。 可以参考 Gatekeeper 冲突文档 来更新 constraint.yaml
不同的策略效果。
kubectl apply -f https://notaryproject.github.io/ratify/library/default/template.yaml
kubectl apply -f https://notaryproject.github.io/ratify/library/default/samples/constraint.yaml
如何在安装 Ratify 配置后更新其配置?
批准配置是 Kubernetes 自定义资源,允许你更新这些资源,而无需重新安装批准。
- 若要更新 AKV 相关配置,请使用名为
KeyManagementProvider
"Ratify"的azurekeyvault
自定义资源。 若要更新受信任的签名相关配置,请使用类型为KeyManagementProvider
“批准inline
”自定义资源。 请按照 文档操作。 - 若要更新公证项目信任策略和存储,请使用批准
Verifier
自定义资源。 按照 文档进行操作。 - 若要对 ACR(或其他符合 OCI 的注册表)进行身份验证和交互,请使用批准商店自定义资源。 请遵循 文档。
如果未使用表示法工具对容器映像进行签名,该怎么办?
本文档适用于在可生成与公证项目兼容的签名的任何工具上独立验证公证项目签名。 Ratify还支持验证其他类型的签名。 有关详细信息,请参阅 Ratify 用户指南。