在 Azure Kubernetes 服务 (AKS) 群集上部署和配置 Microsoft Entra 工作负荷 ID

本文介绍如何使用 Microsoft Entra 工作负荷 ID 部署和配置 Azure Kubernetes 服务(AKS)群集。 本文中的步骤包括:

  • 使用启用 OpenID Connect (OIDC) 颁发者和 Microsoft Entra 工作负荷 ID 的 Azure CLI 创建新的 AKS 群集或更新现有群集。
  • 创建工作负荷标识和 Kubernetes 服务帐户。
  • 配置托管标识以进行令牌联合身份验证。
  • 部署工作负载并使用工作负载标识验证身份。
  • (可选)向群集中的 Pod 授予访问 Azure Key Vault 中机密的权限。

先决条件

  • 如果没有 Azure 试用版订阅,请在开始前创建一个
  • 本文需要 2.47.0 或更高版本的 Azure CLI。
  • 确保用于创建群集的标识具有合适的的最低权限。 有关详细信息,请参阅 Azure Kubernetes 服务 (AKS) 的访问和标识选项
  • 如果你有多个 Azure 订阅,请使用 az account set 命令选择应在其中计收资源费用的相应订阅 ID。

注意

可以使用服务连接器自动配置某些步骤

创建资源组

  • 使用 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}"
    

在 AKS 群集上启用 OIDC 颁发者和Microsoft Entra 工作负荷 ID

可以在新的或现有的 AKS 群集上启用 OIDC 颁发者和 Microsoft Entra 工作负荷 ID。

  • 使用 az aks create 命令和 --enable-oidc-issuer 参数创建 AKS 群集,以启用 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 格式信息。

检索 OIDC 颁发者 URL

  • 获取 OIDC 颁发者 URL,并使用 [az aks show][az-aks-show] 命令将其保存到环境变量。

    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。

创建管理标识

  1. 使用 [az account show][az-account-show] 命令获取订阅 ID 并将其保存到环境变量。

    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][az-identity-show] 命令将其保存到环境变量。

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

创建 Kubernetes 服务帐户

  1. 使用 az aks get-credentials 命令连接到 AKS 群集。

    az aks get-credentials --name "${CLUSTER_NAME}" --resource-group "${RESOURCE_GROUP}"
    
  2. 使用命令 kubectl apply 应用以下清单,创建一个 Kubernetes 服务帐户,并用托管标识的客户端 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
    

创建联合标识凭据

  • 使用 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
    

    注意

    添加联合标识凭据后,传播联合标识凭据需要几秒钟时间。 如果在添加联合标识凭据后立即发出令牌请求,则在刷新缓存之前,请求可能会失败。 若要避免此问题,可以在添加联合标识凭据后添加轻微的延迟。

使用 Azure RBAC 授权创建密钥保管库

以下示例演示如何使用 Azure 基于角色的访问控制 (Azure RBAC) 权限模型向 Pod 授予访问密钥保管库的权限。 有关 Azure Key Vault 的 Azure RBAC 权限模型的详细信息,请参阅使用 Azure RBAC 授予应用程序访问 Azure Key Vault 的权限

  1. 使用 [az keyvault create][az-keyvault-create] 命令创建启用了清除保护和 Azure RBAC 授权的密钥保管库。 如果为清除保护和 Azure RBAC 授权配置了现有密钥保管库,也可以使用它:

    export KEYVAULT_NAME="keyvault-workload-id$RANDOM_ID" # Ensure the key vault name is between 3-24 characters
    az keyvault create \
        --name "${KEYVAULT_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --enable-purge-protection \
        --enable-rbac-authorization
    
  2. 获取密钥保管库资源 ID,并使用 [az keyvault show][az-keyvault-show] 命令将其保存到环境变量。

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

为密钥保管库管理分配 RBAC 权限

  1. 获取调用方对象 ID,并使用 [az ad signed-in-user show][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] 命令在新密钥保管库中创建机密。

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

创建和配置机密访问

  1. 使用 [az keyvault secret set][az-keyvault-secret-set] 命令在密钥保管库中创建机密。

    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][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角色分配给用户分配的托管标识。 此步骤授予托管标识从密钥保管库读取机密的权限。

    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][az-keyvault-show] 命令为密钥保管库 URL 创建环境变量:

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

部署验证 Pod 并测试访问权限

  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. 检查 Pod 中是否通过SECRET_NAME命令设置了kubectl describe环境变量。

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

    如果成功,输出应类似于以下示例:

    SECRET_NAME: ${KEYVAULT_SECRET_NAME}
    
  4. 请确认 pod 可以获取令牌,然后通过 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 无法访问机密,则可能需要等待角色分配传播。 有关详细信息,请参阅 Azure RBAC 疑难解答

在 AKS 群集上禁用 Microsoft Entra 工作负荷 ID

  • 在已启用和配置的 AKS 群集上禁用Microsoft Entra 工作负荷 ID,使用 [az aks update][az-aks-update] 命令使用 --disable-workload-identity 参数更新 AKS 群集。

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

在本文中,您部署了 Kubernetes 集群,并将其配置为使用 Microsoft Entra 工作负载 ID,以便应用程序工作负载可以使用该凭据进行身份验证。 现在,你已准备好部署应用程序并将其配置为将工作负荷标识与最新版 Azure 标识客户端库配合使用。 如果无法重写应用程序以使用最新的客户端库版本,则可以设置应用程序 Pod,以使用托管标识和工作负荷标识作为短期迁移解决方案进行身份验证。