部署及配置 Microsoft Entra 工作負載 ID 於 Azure Kubernetes Service (AKS)叢集中

在本文中,您將學習如何部署並配置使用 Microsoft Entra 工作負載 ID 的 Azure Kubernetes Service (AKS) 叢集。 本文的步驟包括:

  • 使用 Azure CLI 或 Terraform 並啟用 OpenID Connect(OIDC)發行者並啟用 Microsoft Entra 工作負載 ID,建立新 AKS 叢集或更新現有的 AKS 叢集。
  • 建立一個工作負載識別碼和 Kubernetes 服務帳號。
  • 設定權杖同盟的受控識別。
  • 部署工作負載,並使用工作負載身分識別驗證。
  • 可選擇性地讓叢集中的 pod 存取 Azure 金鑰庫中的秘密。

先決條件

  • 如果你沒有Azure帳號,請在開始前先建立一個free帳號。
  • 本文需要 Azure CLI 2.47.0 或更新版本。 如果使用 Azure Cloud Shell,最新版本已經安裝。 執行 az --version 以尋找版本。 如果你需要安裝或升級,請參考 安裝 Azure CLI。
  • 確保您用來建立叢集的身分識別擁有適當的最低權限。 欲了解更多資訊,請參閱存取與身份選項,Azure Kubernetes Service (AKS)。
  • 請確保您的身分具備在金鑰保存庫範圍內建立角色指派的權限,例如 Role Based 存取控制 Administrator 角色。 貢獻者和 金鑰保存庫 貢獻者角色無法建立角色指派。
  • 如果你有多個Azure訂閱,請使用 az account set 指令選擇相應的訂閱 ID,讓資源在該 ID 中計費。
  • Terraform 本地安裝。 安裝說明請參見 Install Terraform。
  • ARM_SUBSCRIPTION_ID環境變數設為你想建立資源的訂閱 ID。 AzureRM 4.x 需要訂閱 ID 來進行規劃與應用操作。

附註

您可以使用「服務連接器」來協助您自動設定某些步驟。 欲了解更多資訊,請參閱 使用 Microsoft Entra 工作負載 ID 的教程:使用服務連接器連接到 Azure Kubernetes Service (AKS) 中的 Azure 儲存體帳戶。

建立 Terraform 設定檔

該main.tf檔案包含 AKS 叢集、管理身份、聯邦身份憑證、Azure Key Vault 以及用於配置與驗證 Microsoft Entra 工作負載 ID 的 Kubernetes 資源定義。

  1. 建立一個名為 main.tf 的檔案,並加入以下程式碼來定義 Terraform 版本並指定Azure提供者:

    terraform {
     required_version = ">= 1.5.0"
     required_providers {
       azurerm = {
         source  = "hashicorp/azurerm"
         version = "~> 4.0"
       }
       kubernetes = {
         source  = "hashicorp/kubernetes"
         version = "~> 2.30"
       }
       random = {
         source  = "hashicorp/random"
         version = "~> 3.6"
       }
     }
    }
    provider "azurerm" {
     features {}
    }
    data "azurerm_client_config" "current" {}
    
  2. 新增以下程式碼以 main.tf 定義可重複使用變數並為所有資源產生唯一名稱:

    resource "random_string" "suffix" {
     length  = 6
     upper   = false
     special = false
     numeric = true
    }
    locals {
     suffix = random_string.suffix.result
     resource_group_name       = "rg-aks-wi-${local.suffix}"
     cluster_name              = "akswi${local.suffix}"
     managed_identity_name     = "uami-wi-${local.suffix}"
     federated_credential_name = "fic-wi-${local.suffix}"
     key_vault_name            = lower(substr("kvwi${local.suffix}", 0, 24))
     secret_name               = "secret-${local.suffix}"
     service_account_name      = "workload-sa-${local.suffix}"
     service_account_namespace = "default"
     workload_identity_subject = "system:serviceaccount:${local.service_account_namespace}:${local.service_account_name}"
    }
    

建立資源群組

使用 az group create 命令建立資源群組。

export RANDOM_ID="$(openssl rand -hex 3)"
export RESOURCE_GROUP="myResourceGroup$RANDOM_ID"
export LOCATION="<your-preferred-region>"
az group create --name "${RESOURCE_GROUP}" --location "${LOCATION}"

將以下程式碼加入 main.tf 以建立Azure資源群組。 更新 location 值,使其符合你偏好的Azure區域。

resource "azurerm_resource_group" "this" {
 name     = local.resource_group_name
 location = "eastus"
}

在 AKS 叢集啟用 OIDC 發行者及 Microsoft Entra 工作負載 ID

你可以在新建或現有的 AKS 叢集上啟用 OIDC 發行者和 Microsoft Entra 工作負載 ID。

使用 az aks create 指令建立 AKS 叢集,並使用 --enable-oidc-issuer 參數啟用 OIDC 發行器,並啟用 --enable-workload-identity 參數以啟用 Microsoft Entra 工作負載 ID。 下列範例會建立具有單一節點的叢集:

export CLUSTER_NAME="myAKSCluster$RANDOM_ID"
az aks create \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --enable-oidc-issuer \
    --enable-workload-identity \
    --generate-ssh-keys

在幾分鐘之後,此命令就會完成,並以 JSON 格式傳回叢集的相關資訊。

在 main.tf 加入以下程式碼,即可建立一個啟用 OIDC 發行者及 Microsoft Entra 工作負載 ID 的 AKS 叢集:

resource "azurerm_kubernetes_cluster" "this" {
 name                              = local.cluster_name
 location                          = azurerm_resource_group.this.location
 resource_group_name               = azurerm_resource_group.this.name
 dns_prefix                        = local.cluster_name
 oidc_issuer_enabled               = true
 workload_identity_enabled         = true
 role_based_access_control_enabled = true
 default_node_pool {
   name       = "system"
   node_count = 1
   vm_size    = "Standard_B4ms"
 }
 identity {
   type = "SystemAssigned"
 }
}

擷取 OIDC 簽發者 URL

用指令 az aks show 取得 OIDC 發行者的 URL,並存到環境變數。

export AKS_OIDC_ISSUER="$(az aks show --name "${CLUSTER_NAME}" \
    --resource-group "${RESOURCE_GROUP}" \
    --query "oidcIssuerProfile.issuerUrl" \
    --output tsv)"

環境變數應包含與下列範例類似的簽發者 URL:

https://eastus.oic.prod-aks.azure.com/00000000-0000-0000-0000-000000000000/11111111-1111-1111-1111-111111111111/

根據預設,簽發者會設定為使用基底 URL https://{region}.oic.prod-aks.azure.com/{tenant_id}/{uuid},其中 {region} 的值會符合作為 AKS 叢集部署目的地的位置。 該值 {uuid} 代表 OIDC 鍵,是每個叢集隨機產生且不可變的 GUID。

新增以下程式碼 main.tf 以取得 OIDC 發行者的網址:

output "oidc_issuer_url" {
 value = azurerm_kubernetes_cluster.this.oidc_issuer_url
}

建立受控識別

  1. 取得你的訂閱 ID,並用指令 az account show 儲存到環境變數。

    export SUBSCRIPTION="$(az account show --query id --output tsv)"
    
  2. 使用 az identity create 命令建立使用者指派的受控識別。

    export USER_ASSIGNED_IDENTITY_NAME="myIdentity$RANDOM_ID"
    az identity create \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --subscription "${SUBSCRIPTION}"
    

    下列輸出範例顯示已成功建立受控識別:

    {
      "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/myResourceGroupxxxxxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentityxxxxxx",
      "location": "eastus",
      "name": "myIdentityxxxxxx",
      "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "resourceGroup": "myResourceGroupxxxxxx",
      "systemData": null,
      "tags": {},
      "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    
  3. 取得管理身份的客戶端 ID,並用指令 az identity show 儲存到環境變數。

    export USER_ASSIGNED_CLIENT_ID="$(az identity show \
        --resource-group "${RESOURCE_GROUP}" \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --query 'clientId' \
        --output tsv)"
    

新增以下程式碼 main.tf 以建立管理身份:

resource "azurerm_user_assigned_identity" "this" {
 name                = local.managed_identity_name
 location            = azurerm_resource_group.this.location
 resource_group_name = azurerm_resource_group.this.name
}

建立 Kubernetes 服務帳戶

  1. 使用 az aks get-credentials 命令連線至您的 AKS 叢集。

    az aks get-credentials --name "${CLUSTER_NAME}" --resource-group "${RESOURCE_GROUP}"
    
  2. 建立 Kubernetes 服務帳戶,並使用 kubectl apply 命令套用下列資訊清單,使用受控識別的用戶端 ID 為其加上註解。

    export SERVICE_ACCOUNT_NAME="workload-identity-sa$RANDOM_ID"
    export SERVICE_ACCOUNT_NAMESPACE="default"
    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
    

    下列輸出顯示工作負載身分識別建立成功:

    serviceaccount/workload-identity-sa created
    
  1. 新增以下程式碼來 main.tf 設定 Kubernetes 存取權限,允許建立 Kubernetes 資源:

    data "azurerm_kubernetes_cluster" "this" {
     name                = azurerm_kubernetes_cluster.this.name
     resource_group_name = azurerm_resource_group.this.name
    }
    provider "kubernetes" {
     host                   = data.azurerm_kubernetes_cluster.this.kube_config[0].host
     client_certificate     = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_certificate)
     client_key             = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_key)
     cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].cluster_ca_certificate)
    }
    
  2. 將下列程式碼新增至 main.tf,以建立 Kubernetes 服務帳戶,並使用受控識別的用戶端識別碼為其加上註解:

    resource "kubernetes_service_account" "this" {
     metadata {
       name      = local.service_account_name
       namespace = local.service_account_namespace
       annotations = {
         "azure.workload.identity/client-id" = azurerm_user_assigned_identity.this.client_id
       }
     }
    }
    

建立同盟身分識別認證

使用 az identity federated-credential create 指令建立一個聯邦身份憑證,連接管理身份、服務帳號發行者與主體。

export FEDERATED_IDENTITY_CREDENTIAL_NAME="myFedIdentity$RANDOM_ID"
az identity federated-credential create \
    --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} \
    --identity-name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP}" \
    --issuer "${AKS_OIDC_ISSUER}" \
    --subject system:serviceaccount:"${SERVICE_ACCOUNT_NAMESPACE}":"${SERVICE_ACCOUNT_NAME}" \
    --audience api://AzureADTokenExchange

附註

新增同盟身分認證後,需要幾秒鐘的時間才能傳播。 如果在新增同盟身分識別認證後立即提出權杖要求,在重新整理快取之前,要求可能會失敗。 若要避免此問題,您可以在新增同盟身分識別認證之後稍待片刻,再提出權杖要求。

Warning

上述受眾是 Microsoft Entra 工作負載識別碼的預設且推薦對象。 這個數值是全域且在所有 Azure 雲端中一致的,改變受眾值可能會破壞與現有設定的相容性,除非明確要求,否則不建議這麼做。

加入以下程式碼 main.tf ,即可在管理身份、服務帳戶發行者與主體之間建立聯邦身份憑證:

resource "azurerm_federated_identity_credential" "this" {
 name                = local.federated_credential_name
 resource_group_name = azurerm_resource_group.this.name
 parent_id           = azurerm_user_assigned_identity.this.id
 issuer              = azurerm_kubernetes_cluster.this.oidc_issuer_url
 subject             = local.workload_identity_subject
 audience            = ["api://AzureADTokenExchange"]
}

Warning

上述受眾是 Microsoft Entra 工作負載識別碼的預設且推薦對象。 這個數值是全域且在所有 Azure 雲端中一致的,改變受眾值可能會破壞與現有設定的相容性,除非明確要求,否則不建議這麼做。

欲了解更多關於Microsoft Entra聯邦身份憑證的資訊,請參閱Microsoft Entra ID中聯邦身份憑證的概述。

使用 Azure RBAC 授權建立 Azure 金鑰保存庫

以下步驟使用 Azure 角色基礎存取控制(Azure RBAC)權限模型。 背景說明,請參見「授權應用程式使用 Azure RBAC 存取 Azure 金鑰庫」。

  1. 建立一個具有清除保護和啟用了 Azure RBAC 授權的金鑰保險庫,使用 az keyvault create 指令。 如果現有的金鑰庫同時設定了清除保護和 Azure RBAC 授權,你也可以使用它。

    export KEYVAULT_NAME="kv-workload-id$RANDOM_ID"
    az keyvault create \
        --name "${KEYVAULT_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --enable-purge-protection \
        --enable-rbac-authorization
    
  2. 取得金鑰保險庫的資源 ID,並用指令 az keyvault show 儲存到環境變數。

    export KEYVAULT_RESOURCE_ID=$(az keyvault show --resource-group "${RESOURCE_GROUP}" \
        --name "${KEYVAULT_NAME}" \
        --query id \
        --output tsv)
    

新增以下程式碼,main.tf即可建立一個帶有清除保護且啟用 Azure RBAC 授權的金鑰保險庫:

resource "azurerm_key_vault" "this" {
 name                       = local.key_vault_name
 location                   = azurerm_resource_group.this.location
 resource_group_name        = azurerm_resource_group.this.name
 tenant_id                  = data.azurerm_client_config.current.tenant_id
 sku_name                   = "standard"
 enable_rbac_authorization  = true
 purge_protection_enabled   = true
}

指派適用於 Azure Key Vault 管理的 RBAC 權限

  1. 取得呼叫者物件 ID,並用指令 az ad signed-in-user show 儲存到環境變數。

    export CALLER_OBJECT_ID=$(az ad signed-in-user show --query id -o tsv)
    
  2. 請為自己指定Azure RBAC 金鑰保存庫 秘密官角色,這樣你就能在新key vault中使用 az role assignment create 指令建立秘密。

    az role assignment create --assignee "${CALLER_OBJECT_ID}" \
        --role "Key Vault Secrets Officer" \
        --scope "${KEYVAULT_RESOURCE_ID}"
    

    重要事項

    Azure 角色指派的傳遞時間可能長達 10 分鐘。 如果在下一節建立祕密時回傳403錯誤,請等待角色指派完成傳播,然後重試該命令。 更多資訊請參見 Troubleshoot Azure RBAC。

在 main.tf 中加入以下程式碼,為自己指派 Azure RBAC 金鑰保存庫 秘密管理員 角色,以便能在新的金鑰保存庫中建立秘密,並將 金鑰保存庫 秘密使用者 角色指派給使用者指定的受控身份:

resource "azurerm_role_assignment" "user" {
 scope                = azurerm_key_vault.this.id
 role_definition_name = "Key Vault Secrets Officer"
 principal_id         = data.azurerm_client_config.current.object_id
}
resource "azurerm_role_assignment" "identity" {
 scope                = azurerm_key_vault.this.id
 role_definition_name = "Key Vault Secrets User"
 principal_id         = azurerm_user_assigned_identity.this.principal_id
}

建立與設定秘密存取

  1. 使用 az keyvault secret set 命令在金鑰保存庫中建立秘密。

    建立一個秘密,其名稱會儲存在變數中 KEYVAULT_SECRET_NAME ,並將它的值 Hello! 設在你建立的金鑰庫中。

    export KEYVAULT_SECRET_NAME="my-secret$RANDOM_ID"
    az keyvault secret set \
        --vault-name "${KEYVAULT_NAME}" \
        --name "${KEYVAULT_SECRET_NAME}" \
        --value 'Hello!'
    
  2. 取得使用者指派的管理身份主體 ID,並用指令 az identity show 儲存到環境變數。

    export IDENTITY_PRINCIPAL_ID=$(az identity show \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --query principalId \
        --output tsv)
    
  3. 使用 命令,將 az role assignment create 角色指派給使用者指派受控識別。 此步驟賦予受管理身份從金鑰庫讀取秘密的權限。

    az role assignment create \
        --assignee-object-id "${IDENTITY_PRINCIPAL_ID}" \
        --role "Key Vault Secrets User" \
        --scope "${KEYVAULT_RESOURCE_ID}" \
        --assignee-principal-type ServicePrincipal
    
  4. 請使用 指令 az keyvault show 建立 key vault URL 的環境變數。

    export KEYVAULT_URL="$(az keyvault show \
        --resource-group "${RESOURCE_GROUP}" \
        --name ${KEYVAULT_NAME} \
        --query properties.vaultUri \
        --output tsv)"
    

在 main.tf 加入以下程式碼,以便在金鑰庫中建立機密:

resource "azurerm_key_vault_secret" "this" {
 name         = local.secret_name
 value        = "Hello from Key Vault"
 key_vault_id = azurerm_key_vault.this.id

 depends_on = [azurerm_role_assignment.user]
}

重要事項

Azure 角色指派的傳遞時間可能長達 10 分鐘。 如果terraform apply在建立祕密時回傳403錯誤,請等待角色指派完成傳播,然後重新執行該命令。 更多資訊請參見 Troubleshoot Azure RBAC。

部署驗證 Pod 並測試存取(Azure CLI)

  1. 部署一個 pod 來驗證工作負載身分識別是否能存取金鑰保存庫中的秘密。 以下範例使用 ghcr.io/azure/azure-workload-identity/msal-go 映像檔,其中包含一個範例應用程式,利用 Microsoft Entra 工作負載 ID 從 Azure Key Vault 取得秘密:

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
        name: sample-workload-identity-key-vault
        namespace: ${SERVICE_ACCOUNT_NAMESPACE}
        labels:
            azure.workload.identity/use: "true"
    spec:
        serviceAccountName: ${SERVICE_ACCOUNT_NAME}
        containers:
          - image: ghcr.io/azure/azure-workload-identity/msal-go
            name: oidc
            env:
              - name: KEYVAULT_URL
                value: ${KEYVAULT_URL}
              - name: SECRET_NAME
                value: ${KEYVAULT_SECRET_NAME}
        nodeSelector:
            kubernetes.io/os: linux
    EOF
    
  2. 使用Ready指令,等待 pod 進入 kubectl wait 狀態。

    kubectl wait --namespace ${SERVICE_ACCOUNT_NAMESPACE} --for=condition=Ready pod/sample-workload-identity-key-vault --timeout=120s
    
  3. 用指令SECRET_NAME檢查 pod 裡的環境變數kubectl describe是否已設定。

    kubectl describe pod sample-workload-identity-key-vault | grep "SECRET_NAME:"
    

    如果成功,輸出應該類似下列範例:

    SECRET_NAME: ${KEYVAULT_SECRET_NAME}
    
  4. 確認 pods 是否能取得 token,並用指令 kubectl logs 存取資源。

    kubectl logs sample-workload-identity-key-vault
    

    如果成功,輸出應該類似下列範例:

    I0114 10:35:09.795900       1 main.go:63] "successfully got secret" secret="Hello!"
    

    重要事項

    Azure RBAC 角色分配可能需要長達 10 分鐘才能生效。 如果 Pod 無法存取秘密,您可能需要等候角色指派散佈開來。 更多資訊請參見 Troubleshoot Azure RBAC。

在 AKS 叢集上停用 Microsoft Entra 工作負載 ID

若要在您已啟用並設定 Microsoft Entra 工作負載 ID 的 AKS 叢集上停用它,請使用 `az aks update` 命令並搭配 `--disable-workload-identity` 參數。

az aks update \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --disable-workload-identity

部署驗證 Pod (Terraform)

新增以下程式碼 main.tf 以部署驗證艙,利用工作負載身份存取金鑰庫中的秘密:

resource "kubernetes_pod" "test" {
 metadata {
   name      = "workload-identity-test"
   namespace = local.service_account_namespace
   labels = {
     "azure.workload.identity/use" = "true"
   }
 }
 spec {
   service_account_name = kubernetes_service_account.this.metadata[0].name
   container {
     name  = "test"
     image = "ghcr.io/azure/azure-workload-identity/msal-go"
     env {
       name  = "KEYVAULT_URL"
       value = azurerm_key_vault.this.vault_uri
     }
     env {
       name  = "SECRET_NAME"
       value = azurerm_key_vault_secret.this.name
     }
   }
 }

 depends_on = [
   azurerm_federated_identity_credential.this,
   azurerm_role_assignment.identity,
 ]
}

初始化 Terraform

在包含你 main.tf 檔案的目錄中,使用 terraform init 指令初始化 Terraform。 此命令會下載使用 Terraform 管理 Azure 資源所需的 Azure 提供者。

terraform init

建立 Terraform 執行計畫

使用 terraform plan 命令建立 Terraform 執行計畫。 這個指令會顯示 Terraform 會在你的 Azure 訂閱中建立或修改的資源。

terraform plan

套用 Terraform 組態

在確認執行計畫後,使用 terraform apply 指令套用 Terraform 設定。 此指令會建立或修改你Azure訂閱中 main.tf 檔案中定義的資源。

terraform apply

驗證部署

  1. 使用 az aks get-credentials 命令連線至您的 AKS 叢集。

    az aks get-credentials --name <cluster-name> --resource-group <resource-group>
    
  2. 用指令 kubectl get pods 檢查驗證艙的狀態。

  3. 一旦 pod 達到某個 Ready 狀態,請用 kubectl logs 指令檢查 pod 日誌,確認它能存取 key vault 的秘密。

    kubectl logs workload-identity-test
    

    若成功,輸出類似以下範例:

    I0114 10:35:09.795900       1 main.go:63] "successfully got secret" secret="Hello from Key Vault"
    

    重要事項

    Azure RBAC 角色分配可能需要長達 10 分鐘才能生效。 如果 Pod 無法存取秘密,就等角色分配傳播,然後用指令terraform apply -replace="kubernetes_pod.test"重新建立 pod。 更多資訊請參見 Troubleshoot Azure RBAC。

在本文中,你部署了一個 Kubernetes 叢集,並設定它使用 Microsoft Entra 工作負載 ID,為應用程式工作負載以該憑證認證做準備。 現在,您已準備好部署應用程式,並將其設定為使用工作負載身分,且搭配最新版 Azure Identity 用戶端程式庫。 如果您無法將應用程式重寫為使用最新的用戶端程式庫版本,您可以設定應用程式 Pod,以使用受控識別搭配工作負載身分識別進行驗證,作為短期移轉解決方案。

Service Connector 整合有助於簡化 AKS 工作負載及Azure支援服務的連線設定。 它能安全處理認證與網路設定,並遵循連接 Azure 服務的最佳實務。 如需詳細資訊,請參閱在 AKS 中使用 Microsoft Entra Workload Identity 連線到 Foundry 模型中的 Azure OpenAI,以及 Service Connector 簡介。