在 Azure Kubernetes 服务 (AKS) 中将 Azure 标识提供者连接到 Azure Key Vault 机密存储 CSI 驱动程序
Azure Kubernetes 服务 (AKS) 上的机密存储容器存储接口 (CSI) 驱动程序提供了多种基于标识访问 Azure Key Vault 的方法。 本文概述了何时使用基于角色的访问控制 (RBAC) 或 OpenID Connect (OIDC) 安全模型来访问 Key Vault 和 AKS 群集的方法和最佳做法。
可以使用以下访问方法之一:
CSI 驱动程序的先决条件
- 开始使用之前,请确保完成在 Azure Kubernetes 服务 (AKS) 群集中使用用于机密存储 CSI 驱动程序的 Azure Key Vault 提供程序中的步骤,以在 AKS 群集中启用 Azure Key Vault 机密存储 CSI 驱动程序。
使用 Microsoft Entra 工作负载 ID 进行访问
Microsoft Entra 工作负载 ID 是 Pod 上运行的应用程序使用的标识,可针对其他 Azure 服务(例如软件中的工作负载)进行自身身份验证。 机密存储 CSI 驱动程序与本机 Kubernetes 功能集成,可与外部标识提供者联合。
在此安全模型中,AKS 群集充当令牌颁发者。 然后,Microsoft Entra ID 会使用 OIDC 发现公共签名密钥,并在用它交换 Microsoft Entra 令牌前验证服务帐户令牌的真实性。 要使工作负载用投影到其卷的服务帐户令牌交换 Microsoft Entra 令牌,需要使用 Azure SDK 或 Microsoft 身份验证库 (MSAL) 中的 Azure 标识客户端库
注意
- 此身份验证方法取代了 Microsoft Entra Pod 托管标识(预览版)。 Azure Kubernetes 服务中的开源 Microsoft Entra Pod 托管标识(预览版)已于 2022 年 10 月 24 日弃用。
- Windows 和 Linux 群集都支持 Microsoft Entra 工作负载 ID。
配置工作负载标识
使用
az account set
命令设置订阅。export SUBSCRIPTION_ID=<subscription id> export RESOURCE_GROUP=<resource group name> export UAMI=<name for user assigned identity> export KEYVAULT_NAME=<existing keyvault name> export CLUSTER_NAME=<aks cluster name> az account set --subscription $SUBSCRIPTION_ID
使用
az identity create
命令创建托管标识。az identity create --name $UAMI --resource-group $RESOURCE_GROUP export USER_ASSIGNED_CLIENT_ID="$(az identity show -g $RESOURCE_GROUP --name $UAMI --query 'clientId' -o tsv)" export IDENTITY_TENANT=$(az aks show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP --query identity.tenantId -o tsv)
创建角色分配,以使用
az role assignment create
命令向工作负载标识授予访问密钥保管库机密、访问密钥和证书的权限。export KEYVAULT_SCOPE=$(az keyvault show --name $KEYVAULT_NAME --query id -o tsv) az role assignment create --role "Key Vault Administrator" --assignee $USER_ASSIGNED_CLIENT_ID --scope $KEYVAULT_SCOPE
使用
az aks show
命令获取 AKS 群集 OIDC 颁发者 URL。注意
此步骤假定你已有启用了 OIDC 颁发者 URL 的现有 AKS 群集。 如果未启用它,请参阅使用 OIDC 颁发者更新 AKS 群集以启用它。
export AKS_OIDC_ISSUER="$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query "oidcIssuerProfile.issuerUrl" -o tsv)" echo $AKS_OIDC_ISSUER
在 Microsoft Entra 应用程序、服务帐户颁发者和使用者之间建立联合标识凭据。 使用以下命令获取 Microsoft Entra 应用程序的对象 ID。 确保使用 Kubernetes 服务帐户名称及其命名空间更新
serviceAccountName
和serviceAccountNamespace
的值。export SERVICE_ACCOUNT_NAME="workload-identity-sa" # sample name; can be changed export SERVICE_ACCOUNT_NAMESPACE="default" # can be changed to namespace of your workload cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: azure.workload.identity/client-id: ${USER_ASSIGNED_CLIENT_ID} name: ${SERVICE_ACCOUNT_NAME} namespace: ${SERVICE_ACCOUNT_NAMESPACE} EOF
使用
az identity federated-credential create
命令在托管标识、服务帐户颁发者和使用者之间创建联合标识凭据。export FEDERATED_IDENTITY_NAME="aksfederatedidentity" # can be changed as needed az identity federated-credential create --name $FEDERATED_IDENTITY_NAME --identity-name $UAMI --resource-group $RESOURCE_GROUP --issuer ${AKS_OIDC_ISSUER} --subject system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}
使用
kubectl apply
命令和以下 YAML 脚本部署SecretProviderClass
。cat <<EOF | kubectl apply -f - # This is a SecretProviderClass example using workload identity to access your key vault apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-kvname-wi # needs to be unique per namespace spec: provider: azure parameters: usePodIdentity: "false" clientID: "${USER_ASSIGNED_CLIENT_ID}" # Setting this to use workload identity keyvaultName: ${KEYVAULT_NAME} # Set to the name of your key vault cloudName: "AzureChinaCloud" # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzureChinaCloud objects: | array: - | objectName: secret1 # Set to the name of your secret objectType: secret # object types: secret, key, or cert objectVersion: "" # [OPTIONAL] object versions, default to latest if empty - | objectName: key1 # Set to the name of your key objectType: key objectVersion: "" tenantId: "${IDENTITY_TENANT}" # The tenant ID of the key vault EOF
注意
如果使用
objectAlias
而不是objectName
,请更新 YAML 脚本以进行解释。注意
若要使
SecretProviderClass
正常运行,在objects
部分中引用机密、密钥或证书之前,请确保在 Azure Key Vault 中填充它们。使用
kubectl apply
命令和以下 YAML 脚本部署示例 Pod。cat <<EOF | kubectl apply -f - # This is a sample pod definition for using SecretProviderClass and workload identity to access your key vault kind: Pod apiVersion: v1 metadata: name: busybox-secrets-store-inline-wi labels: azure.workload.identity/use: "true" spec: serviceAccountName: "workload-identity-sa" containers: - name: busybox image: k8sgcr.azk8s.cn/e2e-test-images/busybox:1.29-4 command: - "/bin/sleep" - "10000" volumeMounts: - name: secrets-store01-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store01-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-kvname-wi" EOF
使用托管标识访问
Microsoft Entra 托管 ID 是管理员用来对其他 Azure 服务进行身份验证的标识。 托管标识使用 RBAC 与外部标识提供者联合。
在此安全模型中,可以向共享托管角色的团队成员或租户授予对群集资源的访问权限。 检查角色的范围是否可访问密钥保管库和其他凭据。 在 AKS 群集上启用用于机密存储 CSI 驱动程序的 Azure Key Vault 提供程序时,它会创建一个用户标识。
配置托管标识
使用
az aks show
命令和加载项创建的用户分配的托管标识访问密钥保管库。 你还应当检索标识的clientId
,以便在后续步骤中在创建SecretProviderClass
时使用。az aks show -g <resource-group> -n <cluster-name> --query addonProfiles.azureKeyvaultSecretsProvider.identity.objectId -o tsv az aks show -g <resource-group> -n <cluster-name> --query addonProfiles.azureKeyvaultSecretsProvider.identity.clientId -o tsv
或者,可以使用以下命令创建新的托管标识,并将其分配给虚拟机 (VM) 规模集或分配给可用性集内的每个 VM 实例。
az identity create -g <resource-group> -n <identity-name> az vmss identity assign -g <resource-group> -n <agent-pool-vmss> --identities <identity-resource-id> az vm identity assign -g <resource-group> -n <agent-pool-vm> --identities <identity-resource-id> az identity show -g <resource-group> --name <identity-name> --query 'clientId' -o tsv
使用
az role assignment create
命令创建角色分配,授予标识访问密钥保管库机密、访问密钥和证书的权限。export IDENTITY_OBJECT_ID="$(az identity show -g <resource-group> --name <identity-name> --query 'principalId' -o tsv)" export KEYVAULT_SCOPE=$(az keyvault show --name <key-vault-name> --query id -o tsv) az role assignment create --role "Key Vault Administrator" --assignee $IDENTITY_OBJECT_ID --scope $KEYVAULT_SCOPE
使用以下 YAML 创建
SecretProviderClass
。 确保对userAssignedIdentityID
、keyvaultName
、tenantId
和要从密钥保管库中检索的对象使用自己的值。# This is a SecretProviderClass example using user-assigned identity to access your key vault apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-kvname-user-msi spec: provider: azure parameters: usePodIdentity: "false" useVMManagedIdentity: "true" # Set to true for using managed identity userAssignedIdentityID: <client-id> # Set the clientID of the user-assigned managed identity to use keyvaultName: <key-vault-name> # Set to the name of your key vault cloudName: "AzureChinaCloud" # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud objects: | array: - | objectName: secret1 objectType: secret # object types: secret, key, or cert objectVersion: "" # [OPTIONAL] object versions, default to latest if empty - | objectName: key1 objectType: key objectVersion: "" tenantId: <tenant-id> # The tenant ID of the key vault
注意
如果使用
objectAlias
而不是objectName
,请务必更新 YAML 脚本。注意
若要使
SecretProviderClass
正常运行,在objects
部分中引用机密、密钥或证书之前,请确保在 Azure Key Vault 中填充它们。使用
kubectl apply
命令将SecretProviderClass
应用到群集。kubectl apply -f secretproviderclass.yaml
使用以下 YAML 创建 Pod。
# This is a sample pod definition for using SecretProviderClass and the user-assigned identity to access your key vault kind: Pod apiVersion: v1 metadata: name: busybox-secrets-store-inline-user-msi spec: containers: name: busybox image: k8sgcr.azk8s.cn/e2e-test-images/busybox:1.29-4 command: - "/bin/sleep" - "10000" volumeMounts: - name: secrets-store01-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store01-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-kvname-user-msi"
使用
kubectl apply
命令将 Pod 应用到群集。kubectl apply -f pod.yaml
使用 Key Vault 机密
Pod 启动后,在部署 YAML 中指定的卷路径上装载的内容便可用了。 使用以下命令验证机密并打印测试机密。
使用以下命令显示机密存储中保存的机密。
kubectl exec busybox-secrets-store-inline -- ls /mnt/secrets-store/
使用以下命令显示存储中的机密。 此示例命令会显示测试机密
ExampleSecret
。kubectl exec busybox-secrets-store-inline -- cat /mnt/secrets-store/ExampleSecret
获取证书和密钥
Azure 密钥保管库设计在密钥、机密和证书之间进行了明确区分。 Key Vault 服务的证书功能旨在利用其密钥和机密功能。 创建密钥保管库证书后,它会创建具有相同名称的可寻址密钥和机密。 密钥允许身份验证操作,机密允许以机密形式检索证书值。
密钥保管库证书还包含公共 x509 证书元数据。 密钥保管库将证书的公共组成部分和私用组成部分存储在一个机密中。 可以通过在 SecretProviderClass
中指定 objectType
来获取每个单独的组成部分。 下表显示了哪些对象映射到与证书关联的各种资源:
Object | 返回值 | 返回整个证书链 |
---|---|---|
key |
采用隐私增强邮件 (PEM) 格式的公钥。 | 不可用 |
cert |
采用 PEM 格式的证书。 | 否 |
secret |
采用 PEM 格式的私钥和证书。 | 是 |
在现有群集上禁用加载项
注意
在禁用该加载项之前,请确保没有正在使用 SecretProviderClass
。 当存在 SecretProviderClass
时尝试禁用该加载项会导致出错。
配合使用
az aks disable-addons
命令与azure-keyvault-secrets-provider
加载项,在现有群集中禁用适用于机密存储 CSI 驱动程序的 Azure 密钥保管库提供程序功能。az aks disable-addons --addons azure-keyvault-secrets-provider -g myResourceGroup -n myAKSCluster
注意
在禁用加载项时,现有工作负载应该没有问题,或者不应在已装载的机密中看到任何更新。 如果 Pod 重启,或作为纵向扩展事件的一部分创建新 Pod,该 Pod 将无法启动,因为驱动程序已不再运行。
后续步骤
本文介绍了如何创建和提供用于访问 Azure 密钥保管库的标识。 如果要配置额外的配置选项或执行故障排除,请继续阅读下一篇文章。