在 Azure Kubernetes Service (AKS) 中將您的 Azure 識別提供者連線到 Azure Key Vault 祕密存放區 CSI 驅動程式

Azure Kubernetes Service (AKS) 上的祕密存放區容器儲存體介面 (CSI) 驅動程式會提供各種以身分識別為基礎來存取您 Azure Key Vault 的方法。 本文針對使用角色型存取控制 (RBAC) 或 OpenID Connect (OIDC) 安全性模型來存取金鑰保存庫和 AKS 叢集的時機,概述這些方法與最佳做法。

您可以使用下列其中一種存取方法:

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 Service 中的開放原始碼 Microsoft Entra Pod 受控識別 (預覽版) 已於 2022 年 10 月 24 日起停用。
  • Microsoft Entra 工作負載 ID 同時支援 Windows 和 Linux 叢集。

設定工作負載身分識別

  1. 使用 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
    
  2. 使用 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)
    
  3. 使用 az role assignment create (部分機器翻譯) 命令來建立角色指派,以授與工作負載身分識別權限來存取金鑰保存庫祕密、存取金鑰和憑證。

    重要

    • 如果您的金鑰保存庫已設定 --enable-rbac-authorization 為 ,且您正在使用 keycertificate 類型,請指派 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
    
  4. 使用 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
    
  5. 建立 Microsoft Entra 應用程式、服務帳戶簽發者和主體之間的同盟身分識別認證。 使用下列命令來取得 Microsoft Entra 應用程式的物件識別碼。 確認會使用 Kubernetes 服務帳戶名稱和其命名空間來更新 serviceAccountNameserviceAccountNamespace 的值。

    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
    
  6. 使用 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}
    
  7. 使用 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: ""                         # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud
        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 金鑰保存庫。

  8. 使用 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: registry.k8s.io/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 提供者 (部分機器翻譯) 時,即會建立使用者身分識別。

設定受控身分識別

  1. 使用 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
    
  2. 建立角色指派,以授與身分識別許可權,以使用 az role assignment create 命令存取密鑰保存庫秘密、存取金鑰和憑證。

    重要

    • 如果您的金鑰保存庫已設定 --enable-rbac-authorization 為 ,且您使用 keycertificate 類型,請指派 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 -g <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
    
  3. 使用下列 YAML 來建立 SecretProviderClass。 確認您會針對 userAssignedIdentityIDkeyvaultNametenantId,以及從金鑰保存庫擷取的物件使用自己的值。

    # 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: ""                         # [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 金鑰保存庫。

  4. 使用 kubectl apply 命令,將 SecretProviderClass 套用至您的叢集。

    kubectl apply -f secretproviderclass.yaml
    
  5. 使用下列 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: registry.k8s.io/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"
    
  6. 使用 kubectl apply 命令,將 Pod 套用至您的叢集。

    kubectl apply -f pod.yaml
    

驗證 Key Vault 祕密

Pod 啟動之後,便可使用您在部署 YAML 中指定的磁碟區路徑上掛接的內容。 使用下列命令來驗證您的祕密,並列印測試祕密。

  1. 使用下列命令來顯示祕密存放區中保存的祕密。

    kubectl exec busybox-secrets-store-inline-user-msi -- ls /mnt/secrets-store/
    
  2. 使用下列命令來顯示存放區中的祕密。 此範例命令會顯示測試祕密 ExampleSecret

    kubectl exec busybox-secrets-store-inline-user-msi -- cat /mnt/secrets-store/ExampleSecret
    

取得憑證與金鑰

Azure Key Vault 設計會區分金鑰、秘密和憑證。 Key Vault 服務的憑證功能是設計來使用金鑰和祕密功能。 當您建立金鑰保存庫憑證時,其會以相同名稱建立可定址的金鑰和祕密。 此金鑰允許驗證作業,而祕密允許擷取憑證值作為祕密。

Key Vault 憑證也會包含公用 x509 憑證的中繼資料。 Key Vault 會將憑證的公開和私人元件儲存在秘密中。 您可以藉由在 SecretProviderClass 中指定 objectType 來取得每個個別元件。 下表顯示哪些物件會對應至與憑證相關聯的各種資源:

Object 傳回值 傳回整個憑證鏈結
key 隱私增強郵件 (PEM) 格式的公開金鑰。 N/A
cert PEM 格式的憑證。 No
secret PEM 格式的私密金鑰和憑證。 Yes

停用現有叢集上的附加元件

注意

停用附加元件之前,請確定「沒有」使用中的 SecretProviderClass。 若嘗試在 SecretProviderClass 存在時停用附加元件,則會導致錯誤。

  • 在現有的叢集中,使用 az aks disable-addons (部分機器翻譯) 命令搭配 azure-keyvault-secrets-provider 附加元件,停用適用於祕密存放區 CSI 驅動程式的 Azure Key Vault 提供者功能。

    az aks disable-addons --addons azure-keyvault-secrets-provider -g myResourceGroup -n myAKSCluster
    

注意

如果您停用附加元件,則現有的工作負載應該不會有任何問題或在掛接的祕密中看到任何更新。 進行 Pod 擴大期間,若 Pod 重新啟動或建立新的 Pod,Pod 將因驅動程式不再執行而無法啟動。

下一步

在本文中,您已了解如何建立並提供身分識別來存取 Azure Key Vault。 如果您想要設定額外的設定選項或執行疑難排解,請繼續進行下一篇文章。