排查 AKS 中的 Azure 密钥库机密提供程序加载项问题
本文讨论如何在 Azure Kubernetes 服务(AKS)中使用 Azure 密钥库 机密提供程序加载项时遇到的问题进行故障排除。
注意
本文适用于 Azure 密钥库 机密提供程序的 AKS 托管加载项版本。 如果使用 helm 已安装(自管理)版本,请转到适用于机密存储 CSI 驱动程序 GitHub 的 Azure 密钥库 提供程序文档。
先决条件
Kubernetes kubectl 工具(若要使用 Azure CLI 安装 kubectl ,请运行 az aks install-cli 命令。
在 AKS 群集上启用的 Kubernetes 机密存储 CSI 驱动程序 加载项
客户端 URL (curl) 工具
用于 TCP 连接的 Netcat (
nc
) 命令行工具
故障排除清单
步骤 1:确认群集上已启用 Azure 密钥库 机密提供程序加载项
运行 az aks show 命令以确认加载项在群集上已启用:
az aks show -g <aks-resource-group-name> -n <aks-name> --query 'addonProfiles.azureKeyvaultSecretsProvider'
命令输出应类似于以下文本:
{
"config": null,
"enabled": true,
"identity": {
"clientId": "<client-id>",
"objectId": "<object-id>",
"resourceId": "/subscriptions/<subscription-id>/resourcegroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<azure-key-vault-secrets-provider-identity-name>"
}
}
enabled
如果标志如false
前面的输出所示,则群集上未启用 Azure 密钥库 机密提供程序加载项。 在这种情况下,请参阅用于机密存储 CSI 驱动程序 GitHub 的 Azure 密钥库 提供程序文档,以便进一步进行故障排除。
enabled
如果标志如true
前面的输出所示,则会在群集上启用 Azure 密钥库 机密提供程序加载项。 在这种情况下,请转到本文中的后续步骤。
步骤 2:检查机密存储提供程序和 CSI 驱动程序 Pod 日志
Azure 密钥库机密提供程序加载项日志由提供程序和驱动程序 Pod 生成。 若要排查影响提供程序或驱动程序的问题,请检查运行在应用程序 Pod 所在的同一节点上的 Pod 中的日志。
运行 kubectl get 命令,查找在应用程序 Pod 运行所在的同一节点上运行的机密存储提供程序和 CSI 驱动程序 Pod:
kubectl get pod -l 'app in (secrets-store-provider-azure, secrets-store-csi-driver)' -n kube-system -o wide
运行 kubectl logs 命令,查看机密存储提供程序 Pod 中的日志:
kubectl logs -n kube-system <provider-pod-name> --since=1h | grep ^E
运行 kubectl logs 命令,查看机密存储 CSI 驱动程序 Pod 中的日志:
kubectl logs -n kube-system <csi-driver-pod-name> -c secrets-store --since=1h | grep ^E
收集机密存储提供程序和 CSI 驱动程序 Pod 日志后,根据以下部分中提到的原因分析这些日志,以确定问题和相应的解决方案。
注意
如果打开支持请求,最好包含来自 Azure 密钥库 提供程序和机密存储 CSI 驱动程序的相关日志。
原因 1:无法检索密钥保管库令牌
日志或事件消息中可能会出现以下错误条目:
警告 FailedMount 74s kubelet MountVolume.SetUp 失败,卷“secrets-store-inline”:kubernetes.io/csi:mounter。SetupAt failed: rpc error: code = Unknown desc = failed to mount secrets store objects for pod default/test, err: rpc error: code = Unknown desc = failed to mount objects, error: failed to get keyvault client: failed to get key vault token: nmi response failed with status code: 404, err: <nil>
发生此错误的原因是 aad-pod-identity 中的节点托管标识 (NMI) 组件返回了有关令牌请求的错误消息。
解决方案 1:检查 NMI Pod 日志
有关此错误以及如何解决此错误的详细信息,请查看 NMI Pod 日志,并参阅 Microsoft Entra Pod 标识故障排除指南。
原因 2:提供程序 Pod 无法访问密钥保管库实例
日志或事件消息中可能会出现以下错误条目:
E1029 17:37:42.461313 1 server.go:54] 无法处理装载请求, 错误:keyvault。BaseClient#GetSecret: 失败发送请求: StatusCode=0 -- 原始错误: 超出上下文截止时间
发生此错误的原因是提供程序 Pod 无法访问密钥保管库实例。 出于以下任何原因,可能会阻止访问:
防火墙规则阻止来自提供程序的出口流量。
在 AKS 群集中配置的网络策略阻止出口流量。
提供程序 Pod 在主机网络上运行。 如果策略阻止此流量或在节点上发生网络抖动,则可能会发生故障。
解决方案 2:检查网络策略、允许列表和节点连接
若要解决此问题,请执行以下操作:
将提供程序 Pod 置于允许列表上。
检查配置为阻止流量的策略。
确保节点已连接到 Microsoft Entra ID 和密钥保管库。
若要测试从主机网络上运行的 Pod 到 Azure 密钥保管库的连接,请执行以下步骤:
创建 Pod:
cat <<EOF | kubectl apply --filename - apiVersion: v1 kind: Pod metadata: name: curl spec: hostNetwork: true containers: - args: - tail - -f - /dev/null image: curlimages/curl:7.75.0 name: curl dnsPolicy: ClusterFirst restartPolicy: Always EOF
运行 kubectl exec ,在创建的 Pod 中运行命令:
kubectl exec --stdin --tty curl -- sh
使用 Azure 密钥保管库进行身份验证:
curl -X POST 'https://login.microsoftonline.com/<aad-tenant-id>/oauth2/v2.0/token' \ -d 'grant_type=client_credentials&client_id=<azure-client-id>&client_secret=<azure-client-secret>&scope=https://vault.azure.net/.default'
尝试获取已在 Azure 密钥保管库中创建的机密:
curl -X GET 'https://<key-vault-name>.vault.azure.net/secrets/<secret-name>?api-version=7.2' \ -H "Authorization: Bearer <access-token-acquired-above>"
原因 3:SecretProviderClass 自定义资源中用户分配的托管标识不正确
如果遇到 HTTP 错误代码“400”实例,并附带“找不到标识”错误说明,则用户分配的托管标识在自定义资源中 SecretProviderClass
不正确。 完整响应类似于以下文本:
MountVolume.SetUp failed for volume "<volume-name>" :
rpc error:
code = Unknown desc = failed to mount secrets store objects for pod <namespace>/<pod>,
err: rpc error: code = Unknown desc = failed to mount objects,
error: failed to get objectType:secret, objectName:<key-vault-secret-name>, objectVersion:: azure.BearerAuthorizer#WithAuthorization:
Failed to refresh the Token for request to https://<key-vault-name>.vault.azure.net/secrets/<key-vault-secret-name>/?api-version=2016-10-01:
StatusCode=400 -- Original Error: adal: Refresh request failed.
Status Code = '400'.
Response body: {"error":"invalid_request","error_description":"Identity not found"}
Endpoint http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&client_id=<userAssignedIdentityID>&resource=https%!!(MISSING)A(MISSING)%!!(MISSING)F(MISSING)%!!(MISSING)F(MISSING)vault.azure.net
解决方案 3:使用正确的 userAssignedIdentityID 值更新 SecretProviderClass
找到正确的用户分配的托管标识,然后更新 SecretProviderClass
自定义资源以在参数中 userAssignedIdentityID
指定正确的值。 若要查找正确的用户分配托管标识,请在 Azure CLI 中运行以下 az aks show 命令:
az aks show --resource-group <resource-group-name> \
--name <cluster-name> \
--query addonProfiles.azureKeyvaultSecretsProvider.identity.clientId \
--output tsv
有关如何设置 YAML 格式的自定义资源的信息SecretProviderClass
,请参阅“提供标识”的“使用用户分配的托管标识”部分,以访问用于机密存储 CSI 驱动程序的 Azure 密钥库 提供程序文章。
原因 4:密钥保管库专用终结点位于与 AKS 节点不同的虚拟网络上
Azure 密钥库级别不允许使用公用网络访问,AKS 与 密钥库之间的连接是通过专用链接进行的。 但是,密钥库的 AKS 节点和专用终结点位于不同的虚拟网络上。 此方案生成类似于以下文本的消息:
MountVolume.SetUp failed for volume "<volume>" :
rpc error:
code = Unknown desc = failed to mount secrets store objects for pod <namespace>/<pod>,
err: rpc error: code = Unknown desc = failed to mount objects,
error: failed to get objectType:secret, objectName: :<key-vault-secret-name>, objectVersion:: keyvault.BaseClient#GetSecret:
Failure responding to request:
StatusCode=403 -- Original Error: autorest/azure: Service returned an error.
Status=403 Code="Forbidden"
Message="Public network access is disabled and request is not from a trusted service nor via an approved private link.\r\n
Caller: appid=<application-id>;oid=<object-id>;iss=https://sts.windows.net/<id>/;xms_mirid=/subscriptions/<subscription-id>/resourcegroups/<aks-infrastructure-resource-group>/providers/Microsoft.Compute/virtualMachineScaleSets/aks-<nodepool-name>-<nodepool-id>-vmss;xms_az_rid=/subscriptions/<subscription-id>/resourcegroups/<aks-infrastructure-resource-group>/providers/Microsoft.Compute/virtualMachineScaleSets/aks-<nodepool-name>-<nodepool-id>-vmss \r\n
Vault: <keyvaultname>;location=<location>" InnerError={"code":"ForbiddenByConnection"}
解决方案 4a:设置虚拟网络链接和虚拟网络对等互连以连接虚拟网络
修复连接问题通常是一个双重过程:
在专用 Azure DNS 区域级别为 AKS 群集的虚拟网络创建虚拟网络链接。
在 AKS 群集的虚拟网络与密钥库专用终结点的虚拟网络之间添加虚拟网络对等互连。
这些步骤将在以下各节中进行详细说明。
步骤 1:创建虚拟网络链接
连接到 AKS 群集节点,以确定密钥库的完全限定域名(FQDN)是通过公共 IP 地址还是专用 IP 地址解析。 如果收到“公共网络访问已禁用,请求不是来自受信任的服务,也不是通过批准的专用链接”错误消息,则密钥库终结点可能通过公共 IP 地址解析。 若要检查此方案,请运行 nslookup 命令:
nslookup <key-vault-name>.vault.azure.net
如果 FQDN 是通过公共 IP 地址解析的,则命令输出类似于以下文本:
root@aks-<nodepool-name>-<nodepool-id>-vmss<scale-set-instance>:/# nslookup <key-vault-name>.vault.azure.net
Server: 168.63.129.16
Address: 168.63.129.16#53
Non-authoritative answer:
<key-vault-name>.vault.azure.net canonical name = <key-vault-name>.privatelink.vaultcore.azure.net.
<key-vault-name>.privatelink.vaultcore.azure.net canonical name = data-prod.weu.vaultcore.azure.net.
data-prod-weu.vaultcore.azure.net canonical name = data-prod-weu-region.vaultcore.azure.net.
data-prod-weu-region.vaultcore.azure.net canonical name = azkms-prod-weu-b.westeurope.cloudapp.azure.com.
Name: azkms-prod-weu-b.westeurope.cloudapp.azure.com
Address: 20.1.2.3
在这种情况下,请在专用 DNS 区域级别为 AKS 群集的虚拟网络创建虚拟网络链接。 (已为密钥库专用终结点的虚拟网络自动创建虚拟网络链接。
若要创建虚拟网络链接,请执行以下步骤:
在Azure 门户中,搜索并选择私人 DNS区域。
在专用 DNS 区域列表中,选择专用 DNS 区域的名称。 在此示例中,专用 DNS 区域 privatelink.vaultcore.azure.net。
在专用 DNS 区域的导航窗格中,找到 “设置” 标题,然后选择 “虚拟网络链接”。
在虚拟网络链接列表中,选择“ 添加”。
在“ 添加虚拟网络链接 ”页中,完成以下字段。
字段名称 操作 链接名称 输入要用于虚拟网络链接的名称。 订阅 选择要包含虚拟网络链接的订阅的名称。 虚拟网络 选择 AKS 群集的虚拟网络的名称。 选择“确定” 按钮。
完成链接创建过程后,运行 nslookup
命令。 输出现在应类似于以下文本,其中显示了更直接的 DNS 解析:
root@aks-<nodepool-name>-<nodepool-id>-vmss<scale-set-instance>:/# nslookup <key-vault-name>.vault.azure.net
Server: 168.63.129.16
Address: 168.63.129.16#53
Non-authoritative answer:
<key-vault-name>.vault.azure.net canonical name = <key-vault-name>.privatelink.vaultcore.azure.net.
Name: <key-vault-name>.privatelink.vaultcore.azure.net
Address: 172.20.0.4
添加虚拟网络链接后,FQDN 应可通过专用 IP 地址解析。
步骤 2:在虚拟网络之间添加虚拟网络对等互连
如果使用的是专用终结点,则可能已在密钥库级别禁用了公共访问。 因此,AKS 与密钥库之间不存在连接。 可以使用以下 Netcat (nc) 命令测试该配置:
nc -v -w 2 <key-vault-name>.vault.azure.net 443
如果 AKS 与 密钥库之间不可用,则会看到类似于以下文本的输出:
nc: connect to <key-vault-name>.vault.azure.net port 443 (tcp) timed out: Operation now in progress
若要在 AKS 与密钥库之间建立连接,请按照以下步骤在虚拟网络之间添加虚拟网络对等互连:
转到 Azure 门户。
使用以下选项之一按照教程的“创建虚拟网络对等”部分的说明操作:使用Azure 门户文章将虚拟网络连接到虚拟网络对等互连,并验证虚拟网络是否已连接(从一端):
转到 AKS 虚拟网络,并将其对等互连到密钥库专用终结点的虚拟网络。
转到密钥库专用终结点的虚拟网络,并将其对等互连到 AKS 虚拟网络。
在Azure 门户中,搜索并选择其他虚拟网络的名称(在上一步中对等互连的虚拟网络)。
在虚拟网络导航窗格中,找到 “设置” 标题,然后选择“ 对等互连”。
在虚拟网络对等互连页中,验证“名称”列是否包含你在步骤 2 中指定的远程虚拟网络的对等互连链接名称。 此外,请确保该对等互连链接的 对等互连状态 列的值为 Connected。
完成此过程后,可以再次运行 Netcat 命令。 AKS 与密钥库之间的 DNS 解析和连接现在应成功。 此外,请确保成功装载密钥库机密并按预期工作,如以下输出所示:
Connection to <key-vault-name>.vault.azure.net 443 port [tcp/https] succeeded!
解决方案 4b:排查错误代码 403 的问题
通过查看 Azure 密钥库 REST API 错误代码参考文章的 HTTP 403:权限不足部分来排查错误代码“403”问题。
原因 5:注册的 CSI 驱动程序列表中缺少 secrets-store.csi.k8s.io 驱动程序
如果收到有关 Pod 事件中缺少 secrets-store.csi.k8s.io
驱动程序的以下错误消息,则机密存储 CSI 驱动程序 Pod 未在运行应用程序的节点上运行:
警告 FailedMount 42s (x12 over 8m56s) kubelet,akswin000000 MountVolume.SetUp 失败,卷“secrets-store01-inline”:kubernetes.io/csi:mounter。SetUpAt 无法获取 CSI 客户端: 在已注册的 CSI 驱动程序列表中找不到驱动程序名称 secrets-store.csi.k8s.io
解决方案 5:排查在同一节点上运行的机密存储 CSI 驱动程序 Pod 问题
运行以下命令,检索在同一节点上运行的机密存储 CSI 驱动程序 Pod 的状态:
kubectl get pod -l app=secrets-store-csi-driver -n kube-system -o wide
如果 Pod 状态不 Running
或此 Pod 中的任何容器未处于 Ready
状态,请按照“检查机密存储提供程序和 CSI 驱动程序 Pod 日志”中的 步骤继续检查此 Pod 的日志。
原因 6:找不到 SecretProviderClass
描述应用程序 Pod 时,可能会看到以下事件:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedMount 2s (x5 over 10s) kubelet MountVolume.SetUp failed for volume "xxxxxxx" : rpc error: code = Unknown desc = failed to get secretproviderclass xxxxxxx/xxxxxxx, error: SecretProviderClass.secrets-store.csi.x-k8s.io "xxxxxxxxxxxxx" not found
此事件指示 SecretProviderClass
Pod 的卷规范中引用的命名空间与应用程序 Pod 不在同一命名空间中。
解决方案 6a:创建缺少的 SecretProviderClass 资源
确保 SecretProviderClass
Pod 卷规范中引用的资源存在于运行应用程序 Pod 的同一命名空间中。
解决方案 6b:修改应用程序 Pod 的卷规范以引用正确的 SecretProviderClass 资源名称
编辑应用程序 Pod 的卷规范以引用正确的 SecretProviderClass
资源名称:
...
spec:
containers:
...
volumes:
- name: my-volume
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "xxxxxxxxx"
原因 7:请求未经身份验证
请求未经身份验证,密钥库,如“401”错误代码所示。
解决方案 7:排查错误代码 401 的问题
查看 Azure 密钥库 REST API 错误代码参考文章的“HTTP 401:未经身份验证的请求”部分,对错误代码“401”进行故障排除。
原因 8:请求数超过规定的最大值
请求数超过时间范围规定的最大值,如“429”错误代码所示。
解决方案 8:排查错误代码 429 的问题
查看 Azure 密钥库 REST API 错误代码参考文章的“HTTP 429:请求过多”部分,对错误代码“429”进行故障排除。
第三方信息免责声明
本文中提到的第三方产品由 Microsoft 以外的其他公司提供。 Microsoft 不对这些产品的性能或可靠性提供任何明示或暗示性担保。
联系我们寻求帮助
如果你有任何疑问或需要帮助,请创建支持请求或联系 Azure 社区支持。 你还可以将产品反馈提交到 Azure 反馈社区。