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

Azure Kubernetes 服务 (AKS) 是可用于快速部署和管理 Kubernetes 群集的托管式 Kubernetes 服务。 本文介绍如何:

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

本文假定你对 Kubernetes 概念有基本的了解。 有关详细信息,请参阅 Azure Kubernetes 服务 (AKS) 的 Kubernetes 核心概念。 如果你不熟悉 Microsoft Entra Workload ID,请参阅下面的概述一文。

先决条件

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

注意

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

设置活动订阅

首先,通过调用 az account set 命令并传入订阅 ID,将订阅设置为当前活动订阅。

az account set --subscription <subscription-id>

导出环境变量

为了帮助简化配置所需标识的步骤,以下步骤定义了本文示例中引用的环境变量。 请务必将显示的值替换为你自己的值:

export RESOURCE_GROUP="myResourceGroup"
export LOCATION="chinaeast2"
export CLUSTER_NAME="myAKSCluster"
export SERVICE_ACCOUNT_NAMESPACE="default"
export SERVICE_ACCOUNT_NAME="workload-identity-sa"
export SUBSCRIPTION="$(az account show --query id --output tsv)"
export USER_ASSIGNED_IDENTITY_NAME="myIdentity"
export FEDERATED_IDENTITY_CREDENTIAL_NAME="myFedIdentity"
# Include these variables to access key vault secrets from a pod in the cluster.
export KEYVAULT_NAME="keyvault-workload-id"
export KEYVAULT_SECRET_NAME="my-secret"

创建资源组

Azure 资源组是用于部署和管理 Azure 资源的逻辑组。 创建资源组时,系统会提示你指定一个位置。 此位置是资源组元数据的存储位置,也是资源在 Azure 中运行的位置(如果你在创建资源期间未指定其他区域)。

通过调用 az group create 命令创建资源组。

az group create --name "${RESOURCE_GROUP}" --location "${LOCATION}"

以下输出示例显示成功创建资源组:

{
  "id": "/subscriptions/<guid>/resourceGroups/myResourceGroup",
  "location": "eastus",
  "managedBy": null,
  "name": "myResourceGroup",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null
}

创建 AKS 群集

使用带有 --enable-oidc-issuer 参数的 az aks create 命令创建 AKS 群集,以启用 OIDC 颁发者。 以下示例会创建具有一个节点的群集:

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

片刻之后,该命令将会完成,并返回有关群集的 JSON 格式信息。

注意

创建 AKS 群集时,会自动创建另一个资源组来存储 AKS 资源。 有关详细信息,请参阅为何使用 AKS 创建两个资源组?

更新现有的 AKS 群集

可以通过调用带有 --enable-oidc-issuer--enable-workload-identity 参数的 az aks update 命令更新 AKS 群集,以使用 OIDC 颁发者并启用工作负载标识。 以下示例更新现有群集:

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

检索 OIDC 颁发者 URL

若要获取 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。

创建托管标识

调用 az identity create 命令创建托管标识。

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

接下来,为托管标识客户端 ID 创建一个变量。

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

创建 Kubernetes 服务帐户

创建一个 Kubernetes 服务帐户,并使用在上一步创建的托管标识的客户端 ID 对其进行批注。 使用 az aks get-credentials 命令,并替换群集名称和资源组名称的值。

az aks get-credentials --name "${CLUSTER_NAME}" --resource-group "${RESOURCE_GROUP}"

将以下多行输入复制粘贴到 Azure CLI 中。

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 命令在托管标识、服务帐户颁发者和使用者之间创建联合标识凭据。

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

注意

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

部署应用程序

部署应用程序 Pod 时,清单应引用在创建 Kubernetes 服务帐户步骤中创建的服务帐户。 以下清单演示如何引用帐户,特别是 metadata\namespace 和 spec\serviceAccountName 属性。 请确保为 <image> 指定映像,并为 <containerName> 指定容器名称:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: sample-workload-identity
  namespace: ${SERVICE_ACCOUNT_NAMESPACE}
  labels:
    azure.workload.identity/use: "true"  # Required. Only pods with this label can use workload identity.
spec:
  serviceAccountName: ${SERVICE_ACCOUNT_NAME}
  containers:
    - image: <image>
      name: <containerName>
EOF

重要

确保使用工作负载标识的应用程序 Pod 在 Pod 规范中包含标签 azure.workload.identity/use: "true"。否则,Pod 在重启后将失败。

授予访问 Azure Key Vault 的权限

此步骤中的说明演示如何从 Pod 访问 Azure Key Vault 中的机密、密钥或证书。 本部分中的示例为工作负载标识配置对密钥保管库中机密的访问权限,但你可以执行类似的步骤来配置对密钥或证书的访问权限。

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

  1. 创建启用了清除保护功能和 RBAC 授权的新密钥保管库。 如果为清除保护功能和 RBAC 授权配置了现有密钥保管库,也可以使用它:

    export KEYVAULT_RESOURCE_GROUP="myResourceGroup"
    export KEYVAULT_NAME="myKeyVault"
    
    az keyvault create \
        --name "${KEYVAULT_NAME}" \
        --resource-group "${KEYVAULT_RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --enable-purge-protection \
        --enable-rbac-authorization
    
  2. 将 RBAC 密钥保管库机密主管角色分配给自己,以便可以在新的密钥保管库中创建机密:

    export KEYVAULT_RESOURCE_ID=$(az keyvault show --resource-group "${KEYVAULT_RESOURCE_GROUP}" \
        --name "${KEYVAULT_NAME}" \
        --query id \
        --output tsv)
    
    az role assignment create --assignee "\<user-email\>" \
        --role "Key Vault Secrets Officer" \
        --scope "${KEYVAULT_RESOURCE_ID}"
    
  3. 在密钥保管库中创建机密:

    export KEYVAULT_SECRET_NAME="my-secret"
    
    az keyvault secret set \
        --vault-name "${KEYVAULT_NAME}" \
        --name "${KEYVAULT_SECRET_NAME}" \
        --value "Hello\!"
    
  4. 密钥保管库机密用户角色分配给之前创建的用户分配的托管标识。 此步骤授予托管标识从密钥保管库读取机密的权限:

    export IDENTITY_PRINCIPAL_ID=$(az identity show \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --query principalId \
        --output tsv)
    
    az role assignment create \
        --assignee-object-id "${IDENTITY_PRINCIPAL_ID}" \
        --role "Key Vault Secrets User" \
        --scope "${KEYVAULT_RESOURCE_ID}" \
        --assignee-principal-type ServicePrincipal
    
  5. 为密钥保管库 URL 创建环境变量:

    export KEYVAULT_URL="$(az keyvault show \
        --resource-group ${KEYVAULT_RESOURCE_GROUP} \
        --name ${KEYVAULT_NAME} \
        --query properties.vaultUri \
        --output tsv)"
    
  6. 部署引用上服务帐户和密钥保管库 URL 的 Pod:

    cat <<EOF | kubectl apply -f -
    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
    

若要检查 webhook 是否正确注入了所有属性,请使用 kubectl describe 命令:

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

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

      SECRET_NAME:                 ${KEYVAULT_SECRET_NAME}

若要验证 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 角色分配可能需要最多十分钟的时间进行传播。 如果 Pod 无法访问机密,则可能需要等待角色分配传播。 有关详细信息,请参阅 Azure RBAC 疑难解答

禁用工作负载标识

若要在已启用和配置的 AKS 群集上禁用 Microsoft Entra Workload ID,可以运行以下命令:

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

后续步骤

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