Azure Key Vault 证书如何在 AKS 中同步为 Kubernetes Secret?附权限配置与 YAML 示例

这篇文章演示如何在 AKS中启用 Azure Key Vault Secrets Provider add-on,把 Azure Key Vault 中的证书挂载到 Pod,并同步成原生的 Kubernetes TLS Secret。

Secrets Store CSI Driver 支持将 Key Vault 中的 secretkeycertificate 挂载到 Pod,也支持同步成 Kubernetes Secret,并支持自动轮换。

本文使用的方式是:

AKS add-on 创建的托管标识 + SecretProviderClass + Pod 挂载触发同步

一、前置条件

开始前请确保具备以下条件:

  • 已安装 Azure CLI ,版本建议为 2.30.0 或以上
  • 已安装 kubectl ,本地可使用 az aks install-cli 安装。
  • 已有一个可用的 AKS 集群
  • 已有一个 Azure Key Vault ,并且其中已存在要读取的证书对象。若你要把证书同步成 kubernetes.io/tls Secret,建议先将证书导入到 Key Vault。

安装 kubectl

bash 复制代码
az aks install-cli

连接到 AKS 集群:

bash 复制代码
az aks get-credentials --resource-group <resource-group> --name <cluster-name>

二、启用 Azure Key Vault Secrets Provider add-on

在现有 AKS 集群上启用 add-on:

bash 复制代码
az aks enable-addons \
  --addons azure-keyvault-secrets-provider \
  --name <cluster-name> \
  --resource-group <resource-group>

启用后,AKS 会自动部署 Secrets Store CSI DriverAzure Key Vault Provider ,并在 节点资源组 中创建一个名为 azurekeyvaultsecretsprovider-xxxxx 的用户分配托管标识,再自动绑定到 VMSS。这个托管标识后续可用于访问 Key Vault。

你可以先确认 add-on identity 信息:

bash 复制代码
az aks show \
  --resource-group <resource-group> \
  --name <cluster-name> \
  --query addonProfiles.azureKeyvaultSecretsProvider.identity

三、为托管标识授予 Key Vault 访问权限

这里要区分两个概念:

  • clientId :写入 SecretProviderClass.parameters.userAssignedIdentityID
  • objectId:用于给这条托管标识授予 Key Vault 访问权限

获取 clientId,后面会在 SecretProviderClass 中使用:

bash 复制代码
export IDENTITY_CLIENT_ID="$(az aks show \
  --resource-group <resource-group> \
  --name <cluster-name> \
  --query addonProfiles.azureKeyvaultSecretsProvider.identity.clientId \
  -o tsv)"

获取 objectId,用于在 Azure 侧授权:

bash 复制代码
export IDENTITY_OBJECT_ID="$(az aks show \
  --resource-group <resource-group> \
  --name <cluster-name> \
  --query addonProfiles.azureKeyvaultSecretsProvider.identity.objectId \
  -o tsv)"

获取 Key Vault 的资源 ID:

bash 复制代码
export KEYVAULT_SCOPE="$(az keyvault show \
  --name <key-vault-name> \
  --query id -o tsv)"

如果你的Key Vault 使用的是RBAC权限模型,则应授予 Key Vault Secrets User

bash 复制代码
az role assignment create \
  --assignee-object-id $IDENTITY_OBJECT_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Key Vault Secrets User" \
  --scope $KEYVAULT_SCOPE

如果你的 Key Vault 使用的是Access Policy 权限模型,则可以改用以下方式授权:

bash 复制代码
az keyvault set-policy \
  --name <key-vault-name> \
  --object-id $IDENTITY_OBJECT_ID \
  --secret-permissions get

到这里,Azure 侧的身份和权限已经准备完成。接下来回到 Kubernetes 侧,创建 SecretProviderClass,告诉 CSI Driver:去哪个 Key Vault、用哪个身份、读取哪个对象,以及是否同步成原生 Kubernetes Secret。

四、创建 SecretProviderClass

SecretProviderClass 是 CSI Driver 的核心配置对象,用来定义:

  • 访问哪个 Key Vault
  • 使用哪个身份
  • 拉取哪些对象
  • 是否同步为 Kubernetes Secret

下面创建一个 SecretProviderClass,把 Key Vault 中的证书同步成一个名为 web-tls 的原生 Kubernetes TLS Secret:

yaml 复制代码
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: azure-tls
  namespace: argocd
spec:
  provider: azure
  secretObjects:
    - secretName: web-tls
      type: kubernetes.io/tls
      data:
        - objectName: mycert
          key: tls.key
        - objectName: mycert
          key: tls.crt
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: "<client-id>"
    keyvaultName: "<key-vault-name>"
    tenantId: "<tenant-id>"
    objects: |
      array:
        - |
          objectName: mycert
          objectType: secret

这里有两个关键点:

  1. secretObjects 定义了要同步出来的 Kubernetes Secret,名称是 web-tls,类型是 kubernetes.io/tls
  2. objectType: secret 是本文最关键的地方。对于 TLS Secret 场景,这样才能从 Key Vault 中取到证书和私钥,再映射到 tls.crttls.key

其中,userAssignedIdentityID 这里填的就是上一步获取到的 IDENTITY_CLIENT_ID

应用资源:

bash 复制代码
kubectl apply -f secretproviderclass.yaml

不过需要注意,SecretProviderClass 只是定义好了"怎么取",它本身不会自动触发同步。真正的拉取和同步动作,要在 Pod 或 Deployment 通过 CSI volume 引用它之后才会发生。

五、通过 Pod 挂载触发同步

为了让 CSI Driver 真正去 Key Vault 拉取对象并同步 Secret,需要有一个 Pod 或 Deployment 显式引用上一步创建的 SecretProviderClass

下面是一个最小可用的测试 Pod:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: kv-sync
  namespace: argocd
spec:
  containers:
    - name: busybox
      image: busybox
      command: ["/bin/sh", "-c", "sleep 3600"]
      volumeMounts:
        - name: kv
          mountPath: "/mnt/secrets"
          readOnly: true
  volumes:
    - name: kv
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: "azure-tls"

应用资源:

bash 复制代码
kubectl apply -f pod.yaml

当这个 Pod 启动后,CSI Driver 会根据 SecretProviderClass 中的定义:

  1. 使用托管标识访问 Azure Key Vault
  2. 拉取对象 mycert
  3. 将内容挂载到容器内的 /mnt/secrets
  4. secretObjects 的定义同步生成 web-tls 这个 Kubernetes Secret

也就是说,只有 Pod 真正运行并消费了这个 CSI volume 后,web-tls 才会被同步出来。

六、验证是否同步成功

既然同步动作是在 Pod 启动后触发的,那么验证时也应该按这个顺序来:先看 Pod,再看挂载内容,最后看同步出来的 Kubernetes Secret。

先确认 Pod 是否已正常创建:

bash 复制代码
kubectl get pod kv-sync -n argocd

再查看容器内挂载目录是否已有内容:

bash 复制代码
kubectl exec -n argocd kv-sync -- ls /mnt/secrets

最后检查同步出来的 Kubernetes Secret:

bash 复制代码
kubectl get secret web-tls -n argocd
kubectl describe secret web-tls -n argocd

如果 web-tls 成功生成,且类型为 kubernetes.io/tls,说明整条链路已经打通:

AKS add-on identity 已被授权访问 Key Vault,SecretProviderClass 已正确定义对象和同步目标,Pod 也成功触发了挂载与同步。

七、需要注意的几个坑

1. SecretProviderClass 创建了,不代表 Secret 会立刻出现

只有当 Pod / Deployment 真正引用了它,CSI Driver 才会触发拉取和同步。否则你会看到 SecretProviderClass 已存在,但 web-tls 一直没有生成。

2. userAssignedIdentityID 如果填错,Pod 往往会挂载失败

这里应填写 add-on identity 的 clientId。如果误填成 objectId 或其他资源 ID,CSI Driver 无法按预期使用这条托管标识访问 Key Vault。

3. TLS Secret 场景下,如果把 objectType 写成 cert,通常拿不到 tls.key

因为 kubernetes.io/tls Secret 需要同时包含证书和私钥,而官方 TLS 示例建议使用 objectType: secret 来获取这两个内容。

4. 自动轮换后,Kubernetes Secret 更新了,不代表应用一定自动生效

如果应用通过环境变量读取 Secret,通常仍需要重启 Pod;如果是文件挂载方式,则应用需要自己支持监听文件变化或热加载。

5. 使用 subPath 挂载时,轮换后的内容不会自动刷新

这是 Kubernetes 已知限制,不是 Key Vault Provider 本身的问题。

相关推荐
Ashmcracker2 小时前
Codex Desktop如何接入Azure OpenAI?AI Foundry部署GPT‑5.3‑codex 实操
人工智能·gpt·microsoft·azure
http阿拉丁神猫1 天前
kubernetes知识点汇总31-36
云原生·容器·kubernetes
暴力袋鼠哥1 天前
基于 LightGBM 的山东高考智能择校推荐系统设计与实现
python·django·flask
Benszen1 天前
K8S存储管理:Volume、PV/PVC与StorageClass详解
容器·rpc·kubernetes
在荒野的梦想1 天前
Docker + K8s 部署若依微服务 | 从 0 到 1 实战指南(Dockerfile + Harbor + Helm)
docker·微服务·kubernetes
fengyehongWorld1 天前
kubernetes Argo简介
云原生·容器·kubernetes
键盘鼓手苏苏2 天前
Kubernetes与GitOps最佳实践
云原生·kubernetes·k8
恼书:-(空寄2 天前
K8s Ingress 七层网关 + 灰度发布 + HTTPS 实战
容器·kubernetes
不是书本的小明2 天前
ACK+ESS实现K8s节点自动扩缩容
容器·kubernetes