在 Azure Kubernetes 服务 (AKS) 中将 Azure 标识提供者连接到 Azure Key Vault 机密存储 CSI 驱动程序
Azure Kubernetes 服务 (AKS) 上的机密存储容器存储接口 (CSI) 驱动程序提供了多种基于标识访问 Azure Key Vault 的方法。 本文概述了何时使用基于角色的访问控制 (RBAC) 或 OpenID Connect (OIDC) 安全模型来访问 Key Vault 和 AKS 群集的方法和最佳做法。
可以使用以下访问方法之一:
- 具有工作负载 ID 的服务连接器
- 工作负载 ID
- 用户分配的托管标识
了解如何使用服务连接器在 Azure Kubernetes 服务 (AKS) 群集中通过 CSI 驱动程序连接到 Azure 密钥保管库。 在本文中,你将完成以下任务:
- 创建 AKS 群集和 Azure Key Vault。
- 使用服务连接器在 AKS 群集与 Azure Key Vault 之间创建连接。
- 创建一个
SecretProviderClass
CRD 和一个使用 CSI 提供程序的Pod
来测试连接。 - 清理资源。
重要
AKS 预览功能是可选择启用的自助功能。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:
先决条件
- 具有活动订阅的 Azure 帐户。 创建帐户。
- Azure CLI。 使用
az login
命令登录。 - Docker 和 kubectl。 若要在本地安装 kubectl,请使用
az aks install-cli
命令。 - 基本了解容器和 AKS。 首先,需要为 AKS 准备应用程序。
- 开始使用之前,请确保完成在 Azure Kubernetes 服务 (AKS) 群集中使用用于机密存储 CSI 驱动程序的 Azure Key Vault 提供程序中的步骤,以在 AKS 群集中启用 Azure Key Vault 机密存储 CSI 驱动程序。
初始设置
如果是第一次使用服务连接器,请首先运行命令 az provider register 来注册服务连接器和 Kubernetes 配置资源提供程序。
az provider register -n Microsoft.ServiceLinker
az provider register -n Microsoft.KubernetesConfiguration
提示
你可以通过运行命令
az provider show -n "Microsoft.ServiceLinker" --query registrationState
和az provider show -n "Microsoft.KubernetesConfiguration" --query registrationState
来检查是否已注册这些资源提供程序。(可选)使用 Azure CLI 命令获取 AKS 群集支持的目标服务列表。
az aks connection list-support-types --output table
创建 Azure 资源
使用
az group create
命令创建资源组。az group create \ --name <resource-group-name> \ --location <location>
使用
az aks create
命令创建 AKS 群集。 以下示例创建了一个启用了托管标识的单节点 AKS 群集。az aks create \ --resource-group <resource-group-name> \ --name <cluster-name> \ --enable-managed-identity \ --node-count 1
使用
az aks get-credentials
命令连接到群集。az aks get-credentials \ --resource-group <resource-group-name> \ --name <cluster-name>
使用
az keyvault create
命令创建 Azure 密钥保管库。az keyvault create \ --resource-group <resource-group-name> \ --name <key-vault-name> \ --location <location>
使用
az keyvault secret set
命令在密钥保管库中创建一个机密。az keyvault secret set \ --vault-name <key-vault-name> \ --name <secret-name> \ --value <secret-value>
使用服务连接器在 AKS 中创建服务连接(预览版)
可以通过 Azure 门户或 Azure CLI 创建到 Azure 密钥保管库的服务连接。
在 Azure 门户中导航到你的 AKS 群集资源。
在服务菜单中的“设置”下,选择“服务连接器(预览版)”>“创建”。
在“创建连接”页面上的“基本信息”选项卡中,配置以下设置:
- Kubernetes 命名空间:选择“默认”。
- 服务类型:选择“密钥保管库”,然后选中该复选框以启用 Azure 密钥保管库 CSI 提供程序。
- 连接名称:输入此连接的名称。
- 订阅:选择包含密钥保管库的订阅。
- 密钥保管库:选择之前创建的密钥保管库。
- 客户端类型:选择“无”。
选择“查看 + 创建”,然后选择“创建”以创建连接。
测试连接
克隆示例存储库并部署清单文件
使用
git clone
命令克隆示例存储库。git clone https://github.com/Azure-Samples/serviceconnector-aks-samples.git
将目录更改为 Azure 密钥保管库 CSI 提供程序示例的目录。
cd serviceconnector-aks-samples/azure-keyvault-csi-provider
在
secret_provider_class.yaml
文件中,将以下占位符替换为 Azure 密钥保管库信息:- 将
<AZURE_KEYVAULT_NAME>
替换为创建和连接的密钥保管库的名称。 - 将
<AZURE_KEYVAULT_TENANTID>
替换为密钥保管库的租户 ID。 - 将
<AZURE_KEYVAULT_CLIENTID>
替换为azureKeyvaultSecretsProvider
加载项的标识客户端 ID。 - 将
<KEYVAULT_SECRET_NAME>
替换为创建的密钥保管库机密。 例如,ExampleSecret
。
- 将
使用
kubectl apply
命令部署SecretProviderClass
CRD。kubectl apply -f secret_provider_class.yaml
使用
kubectl apply
命令部署Pod
清单文件。该命令在 AKS 群集的默认命名空间中创建名为
sc-demo-keyvault-csi
的 Pod。kubectl apply -f pod.yaml
验证连接
使用
kubectl get
命令验证是否已成功创建 Pod。kubectl get pod/sc-demo-keyvault-csi
Pod 启动后,在部署 YAML 中指定的卷路径上装载的内容便可用了。
使用
kubectl exec
命令显示机密存储中保存的机密。kubectl exec sc-demo-keyvault-csi -- ls /mnt/secrets-store/
使用
kubectl exec
命令显示一个机密。此示例命令显示名为
ExampleSecret
的测试机密。kubectl exec sc-demo-keyvault-csi -- cat /mnt/secrets-store/ExampleSecret
CSI 驱动程序的先决条件
- 开始使用之前,请确保完成在 Azure Kubernetes 服务 (AKS) 群集中使用用于机密存储 CSI 驱动程序的 Azure Key Vault 提供程序中的步骤,以在 AKS 群集中启用 Azure Key Vault 机密存储 CSI 驱动程序。
- Microsoft Entra Workload ID 支持 Windows 和 Linux 群集。
使用 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
命令创建托管标识。注意
此步骤假定你拥有已启用工作负荷标识的现有 AKS 群集。 如果未启用它,请参阅在现有 AKS 群集上启用工作负荷标识来启用。
az identity create --name $UAMI --resource-group $RESOURCE_GROUP export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group $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
命令向工作负载标识授予访问密钥保管库机密、访问密钥和证书的权限。重要
- 如果密钥保管库已使用
--enable-rbac-authorization
进行设置,并且你使用key
或certificate
类型,则分配Key Vault Certificate User
角色以授予权限。 - 如果密钥保管库已使用
--enable-rbac-authorization
进行设置,并且你使用secret
类型,则分配Key Vault Secrets User
角色。 - 如果密钥保管库未使用
--enable-rbac-authorization
进行设置,则可将az keyvault set-policy
命令与--key-permissions get
、--certificate-permissions get
或--secret-permissions get
参数一起使用,以创建密钥保管库策略来授予对密钥、证书或机密的访问权限。 例如:
az keyvault set-policy --name $KEYVAULT_NAME --key-permissions get --object-id $IDENTITY_OBJECT_ID
export KEYVAULT_SCOPE=$(az keyvault show --name $KEYVAULT_NAME --query id -o tsv) # Example command for key vault with RBAC enabled using `key` type az role assignment create --role "Key Vault Certificate User" --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
CSI 驱动程序的先决条件
- 开始使用之前,请确保完成在 Azure Kubernetes 服务 (AKS) 群集中使用用于机密存储 CSI 驱动程序的 Azure Key Vault 提供程序中的步骤,以在 AKS 群集中启用 Azure Key Vault 机密存储 CSI 驱动程序。
使用托管标识访问
Microsoft Entra 托管 ID 是管理员用来对其他 Azure 服务进行身份验证的标识。 托管标识使用 RBAC 与外部标识提供者联合。
在此安全模型中,可以向共享托管角色的团队成员或租户授予对群集资源的访问权限。 检查角色的范围是否可访问密钥保管库和其他凭据。 在 AKS 群集上启用用于机密存储 CSI 驱动程序的 Azure Key Vault 提供程序时,它会创建一个用户标识。
配置托管标识
使用
az aks show
命令和加载项创建的用户分配的托管标识访问密钥保管库。 你还应当检索标识的clientId
,以便在后续步骤中在创建SecretProviderClass
时使用。az aks show --resource-group <resource-group> --name <cluster-name> --query addonProfiles.azureKeyvaultSecretsProvider.identity.objectId -o tsv az aks show --resource-group <resource-group> --name <cluster-name> --query addonProfiles.azureKeyvaultSecretsProvider.identity.clientId -o tsv
或者,可以使用以下命令创建新的托管标识,并将其分配给虚拟机 (VM) 规模集或分配给可用性集内的每个 VM 实例。
az identity create --resource-group <resource-group> --name <identity-name> az vmss identity assign --resource-group <resource-group> --name <agent-pool-vmss> --identities <identity-resource-id> az vm identity assign --resource-group <resource-group> --name <agent-pool-vm> --identities <identity-resource-id> az identity show --resource-group <resource-group> --name <identity-name> --query 'clientId' -o tsv
创建角色分配,以使用
az role assignment create
命令向标识授予访问密钥保管库机密、访问密钥和证书的权限。重要
- 如果密钥保管库已使用
--enable-rbac-authorization
进行设置,并且你使用key
或certificate
类型,则分配Key Vault Certificate User
角色。 - 如果密钥保管库已使用
--enable-rbac-authorization
进行设置,并且你使用secret
类型,则分配Key Vault Secrets User
角色。 - 如果密钥保管库未使用
--enable-rbac-authorization
进行设置,则可将az keyvault set-policy
命令与--key-permissions get
、--certificate-permissions get
或--secret-permissions get
参数一起使用,以创建密钥保管库策略来授予对密钥、证书或机密的访问权限。 例如:
az keyvault set-policy --name $KEYVAULT_NAME --key-permissions get --object-id $IDENTITY_OBJECT_ID
export IDENTITY_OBJECT_ID="$(az identity show --resource-group <resource-group> --name <identity-name> --query 'principalId' -o tsv)" export KEYVAULT_SCOPE=$(az keyvault show --name <key-vault-name> --query id -o tsv) # Example command for key vault with RBAC enabled using `key` type az role assignment create --role "Key Vault Certificate User" --assignee $USER_ASSIGNED_CLIENT_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-user-msi -- ls /mnt/secrets-store/
使用以下命令显示存储中的机密。 此示例命令会显示测试机密
ExampleSecret
。kubectl exec busybox-secrets-store-inline-user-msi -- 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 --resource-group myResourceGroup --name myAKSCluster
注意
在禁用加载项时,现有工作负载应该没有问题,或者不应在已装载的机密中看到任何更新。 如果 Pod 重启,或作为纵向扩展事件的一部分创建新 Pod,该 Pod 将无法启动,因为驱动程序已不再运行。
后续步骤
本文介绍了如何创建和提供用于访问 Azure 密钥保管库的标识。 如果要配置额外的配置选项或执行故障排除,请继续阅读下一篇文章。
如果你要配置额外的配置选项或执行故障排除,请参阅适用于 AKS 中机密存储 CSI 驱动程序的 Azure 密钥保管库提供程序的配置选项和故障排除资源。