在 Azure Kubernetes 服务 (AKS) 中使用托管标识

Azure Kubernetes 服务 (AKS) 群集需要标识才能访问负载均衡器和托管磁盘等 Azure 资源。 标识可以是托管标识,也可以是服务主体。

本文详细介绍如何在新的或现有的 AKS 群集上启用以下托管标识类型:

  • 系统分配的托管标识
  • 自带用户分配的托管标识
  • 预先创建的 kubelet 托管标识

概述

部署 AKS 群集时,会自动创建系统分配的托管标识,并由 Azure 平台进行管理,因此无需预配或轮换任何机密。 有关详细信息,请参阅 Azure 资源的托管标识

AKS 不会自动创建服务主体,因此你需要自行创建。 使用服务主体的群集最终会过期,必须续订服务主体以避免对集群身份验证产生影响。 管理服务主体会增加复杂性,因此改用托管标识会更方便。 服务主体和托管标识适用相同的权限要求。 托管标识使用基于证书的身份验证。 每个托管标识的凭据的有效期为 90 天,在 45 天后轮换。

AKS 使用系统分配和用户分配的托管标识类型,这些标识是不可变的。 不要将这些标识类型与 Microsoft Entra 工作负载标识相混淆,后者旨在供 Pod 上运行的应用程序使用。

重要

Azure Kubernetes 服务中的开源 Microsoft Entra Pod 托管标识(预览版)已于 2022 年 10 月 24 日弃用,该项目已于 2023 年 9 月存档。 有关详细信息,请查看弃用通知。 AKS 托管加载项将于 2024 年 9 月开始弃用。

建议你首先查看 Microsoft Entra 工作负载 ID 概述。 Entra 工作负载 ID 身份验证取代了 Microsoft Entra Pod 托管标识(预览版),并且是使 Pod 上运行的应用程序能够针对支持它的其他 Azure 服务自行进行身份验证的建议方法。

开始之前

限制

  • 不支持移动或迁移启用了托管标识的群集的租户。
  • 如果群集启用了 Microsoft Entra pod 托管标识 (aad-pod-identity),节点托管标识 (NMI) pod 将修改节点的 iptable,以拦截对 Azure 实例元数据终结点 (IMDS) 的调用。 此配置意味着对元数据终结点发出的任何请求都将被 NMI 拦截,即使 pod 不使用 aad-pod-identity。 可以将 AzurePodIdentityException CRD 配置为通知 aad-pod-identity 应在不使用 NMI 进行任何处理的情况下,代理与 CRD 中定义的标签匹配的 pod 所发起的对元数据终结点的任何请求。 应通过配置 AzurePodIdentityException CRD 在 aad-pod-identity 中排除在 kubernetes.azure.com/managedby: aks 命名空间中具有 kubernetes.azure.com/managedby: aks 标签的系统 pod。
  • 如果使用的是自定义专用 DNS 区域,则 AKS 不支持使用系统分配的托管标识。

托管标识摘要

AKS 对内置服务和加载项使用多个托管标识。

标识 名称 使用案例 默认权限 自带标识
控制面板 AKS 群集名称 由 AKS 控制平面组件用于管理群集资源,包括入口负载均衡器和 AKS 管理的公共 IP、群集自动缩放程序、Azure 磁盘、文件、Blob CSI 驱动程序。 节点资源组的参与者角色 支持
Kubelet AKS Cluster Name-agentpool 使用 Azure 容器注册表 (ACR) 进行身份验证。 不适用(适用于 kubernetes v1.15+) 支持
加载项 AzureNPM 无需标识。 不适用
加载项 AzureCNI 网络监视 无需标识。 不适用
加载项 azure-policy (gatekeeper) 无需标识。 不适用
加载项 azure-policy 无需标识。 不适用
加载项 Calico 无需标识。 不适用
加载项 仪表板 无需标识。 不适用
加载项 应用程序路由 管理 Azure DNS 和 Azure Key Vault 证书 适用于 Key Vault 的 Key Vault 机密用户角色、适用于 DNS 区域的 DNZ 区域参与者角色、适用于专用 DNS 区域的专用 DNS 区域参与者角色
加载项 HTTPApplicationRouting 管理所需的网络资源。 节点资源组的读取者角色,DNS 区域的参与者角色
加载项 入口应用程序网关 管理所需的网络资源。 节点资源组的参与者角色
加载项 omsagent 用于将 AKS 指标发送到 Azure Monitor。 “监视指标发布者”角色
加载项 Virtual-Node (ACIConnector) 管理 Azure 容器实例 (ACI) 所需的网络资源。 节点资源组的参与者角色
工作负载标识 Microsoft Entra 工作负载 ID 使应用程序能够使用 Microsoft Entra 工作负载 ID 安全地访问云资源。 空值

在新的 AKS 群集上启用托管标识

注意

如果你未指定自己的 kubelet 托管标识,AKS 将在节点资源组中创建用户分配的 kubelet 标识。

注意

如果群集已使用托管标识,并且标识已更改,例如你将群集标识类型从“系统分配”更新为“用户分配”,那么控制平面组件将延迟切换到新标识。 控制平面组件持续使用旧标识,直到其令牌过期。 刷新令牌后,这些组件会切换到新标识。 此过程可能需要几小时的时间。

  1. 使用 az group create 命令创建 Azure 资源组。

    az group create --name myResourceGroup --location westus2
    
  2. 使用 az aks create 命令创建 AKS 群集。

    az aks create -g myResourceGroup -n myManagedCluster --enable-managed-identity
    
  3. 使用 az aks get-credentials 命令获取凭据以访问群集。

    az aks get-credentials --resource-group myResourceGroup --name myManagedCluster
    

在现有 AKS 群集上启用托管标识

若要将使用服务主体的现有 AKS 群集更新为使用系统分配的托管标识,请运行 az aks update 命令。

az aks update -g myResourceGroup -n myManagedCluster --enable-managed-identity

更新集群后,控制平面和 Pod 将使用托管标识。 Kubelet 会继续使用服务主体,直到你升级代理池。 可以在节点上使用 az aks nodepool upgrade --resource-group myResourceGroup --cluster-name myAKSCluster --name mynodepool --node-image-only 命令更新到托管标识。 节点池升级会导致 AKS 群集停机,因为节点池中的节点将被封锁/排空,然后重置映像。

注意

更新集群时请牢记以下信息:

  • 仅当有要使用的 VHD 更新时,更新才有效。 如果你运行的是最新的 VHD,则需要等到下一个 VHD 可用才能执行更新。

  • Azure CLI 可以确保你的插件权限在迁移后正确设置。 如果不使用 Azure CLI 执行迁移操作,则需要自行处理插件身份的权限。 有关使用 Azure 资源管理器 (ARM) 模板的示例,请参阅使用 ARM 模板分配 Azure 角色

  • 如果群集使用 --attach-acr 从 Azure 容器注册表的映像中进行拉取,则需要在更新集群后运行 az aks update --resource-group myResourceGroup --name myAKSCluster --attach-acr <ACR resource ID>,以便让新建的用于托管标识的 kubelet 能够获得从 ACR 进行拉取的权限。 否则,升级后将无法从 ACR 进行拉取。

为托管标识添加角色分配

如果你创建并使用自己的 VNet、附加的 Azure 磁盘、静态 IP 地址、路由表或用户分配的 kubelet 标识,并且其中的资源位于工作器节点资源组的外部,则 Azure CLI 将自动添加角色分配。 如果使用 ARM 模板或其他方法,则需要使用群集托管标识的主体 ID 来执行角色分配。

如果你没有使用 Azure CLI,而是使用自己的 VNet、附加的 Azure 磁盘、静态 IP 地址、路由表或用户分配的 kubelet 标识,并且它们位于工作器节点资源组的外部,则建议使用用户分配的控制平面托管标识。 为了控制平面使用系统分配的托管标识,我们在创建集群之前无法获取标识 ID,这会延迟角色分配生效。

获取托管标识的主体 ID

  • 使用 az identity show 命令获取现有标识的主体 ID。

    az identity show --ids <identity-resource-id>
    

    输出应与下面的示例输出类似:

    {
      "clientId": "<client-id>",
      "id": "/subscriptions/<subscriptionid>/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity",
      "location": "chinaeast2",
      "name": "myIdentity",
      "principalId": "<principal-id>",
      "resourceGroup": "myResourceGroup",
      "tags": {},
      "tenantId": "<tenant-id>",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    

添加角色分配

对于默认工作器节点资源组外部的 VNet、附加的 Azure 磁盘、静态 IP 地址或路由表,需要对自定义资源组分配 Contributor 角色。

  • 使用 az role assignment create 命令在自定义资源组上分配 Contributor 角色。

    az role assignment create --assignee <control-plane-identity-principal-id> --role "Contributor" --scope "<custom-resource-group-resource-id>"
    

对于默认工作器节点资源组外部的用户分配的 kubelet 标识,需要在 kubelet 标识上为控制平面托管标识分配托管标识操作员角色。

  • 使用 az role assignment create 命令在 kubelet 标识上分配 Managed Identity Operator 角色。

    az role assignment create --assignee  <control-plane-identity-principal-id> --role "Managed Identity Operator" --scope "<kubelet-identity-resource-id>"
    

注意

向群集托管标识授予的权限最长可能需要 60 分钟才能填充。

自带托管标识

使用用户分配的托管标识创建群集

控制平面的自定义用户分配托管标识允许在集群创建之前访问现有身份。 此功能适用于多种场景,例如将自定义 VNet 或 outboundType UDR 与预先创建的托管标识结合使用。

注意

如果你未指定自己的 kubelet 托管标识,AKS 将在节点资源组中创建用户分配的 kubelet 标识。

  • 如果你没有托管标识,请使用 az identity create 命令创建一个。

    az identity create --name myIdentity --resource-group myResourceGroup
    

    输出应与下面的示例输出类似:

    {                                  
      "clientId": "<client-id>",
      "clientSecretUrl": "<clientSecretUrl>",
      "id": "/subscriptions/<subscriptionid>/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity", 
      "location": "chinaeast2",
      "name": "myIdentity",
      "principalId": "<principal-id>",
      "resourceGroup": "myResourceGroup",                       
      "tags": {},
      "tenantId": "<tenant-id>",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    

注意

向群集托管标识授予的权限最长可能需要 60 分钟才能填充完成。

  • 在创建群集之前,请使用 az role assignment create 命令[为托管标识添加角色分配][add-role-assignment-for-managed-identity]。

  • 使用用户分配的托管标识创建群集。

    az aks create \
        --resource-group myResourceGroup \
        --name myManagedCluster \
        --network-plugin azure \
        --vnet-subnet-id <subnet-id> \
        --dns-service-ip 10.2.0.10 \
        --service-cidr 10.2.0.0/24 \
        --enable-managed-identity \
        --assign-identity <identity-resource-id>
    

在现有群集上更新托管标识

注意

将控制平面的托管标识从“系统分配”迁移到“用户分配”不会导致控制平面和代理池停机。 同时,控制平面组件将继续使用旧的系统分配的标识数小时,直到下一次令牌刷新为止。

  • 如果你没有托管标识,请使用 az identity create 命令创建一个。

    az identity create --name myIdentity --resource-group myResourceGroup
    

    输出应与下面的示例输出类似:

    {                                  
      "clientId": "<client-id>",
      "clientSecretUrl": "<clientSecretUrl>",
      "id": "/subscriptions/<subscriptionid>/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity", 
      "location": "chinaeast2",
      "name": "myIdentity",
      "principalId": "<principal-id>",
      "resourceGroup": "myResourceGroup",                       
      "tags": {},
      "tenantId": "<tenant-id>",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    
  • 为控制平面创建自定义用户分配的托管标识后,使用 az role assignment create 命令[为托管标识添加角色分配][add-role-assignment-for-managed-identity]。

  • 使用 az aks update 命令更新具有现有标识的群集。 请确保通过包含 assign-identity 参数为控制平面的托管标识提供资源 ID。

    az aks update \
        --resource-group myResourceGroup \
        --name myManagedCluster \
        --enable-managed-identity \
        --assign-identity <identity-resource-id> 
    

    使用你自己的 kubelet 托管标识成功更新 AKS 群集后,应会显示类似于以下示例输出的信息:

      "identity": {
        "principalId": null,
        "tenantId": null,
        "type": "UserAssigned",
        "userAssignedIdentities": {
          "/subscriptions/<subscriptionid>/resourcegroups/resourcegroups/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity": {
            "clientId": "<client-id>",
            "principalId": "<principal-id>"
          }
        }
      },
    

使用预先创建的 kubelet 托管标识

使用 Kubelet 标识可以在创建群集之前访问现有标识。 此功能可以实现使用预先创建的托管标识连接到 ACR 等方案。

预先创建的 kubelet 标识的限制

  • 仅适用于用户分配的托管群集。
  • 目前中国东部和中国北部区域不支持由世纪互联运营的 Azure。

创建用户分配的托管标识

控制平面托管标识

  • 如果你没有控制平面的托管标识,请使用 az identity create 创建一个。

    az identity create --name myIdentity --resource-group myResourceGroup
    

    输出应与下面的示例输出类似:

    {                                  
      "clientId": "<client-id>",
      "clientSecretUrl": "<clientSecretUrl>",
      "id": "/subscriptions/<subscriptionid>/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity", 
      "location": "chinaeast2",
      "name": "myIdentity",
      "principalId": "<principal-id>",
      "resourceGroup": "myResourceGroup",                       
      "tags": {},
      "tenantId": "<tenant-id>",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    

kubelet 托管标识

  • 如果你没有 kubelet 托管标识,请使用 az identity create 命令创建一个。

    az identity create --name myKubeletIdentity --resource-group myResourceGroup
    

    输出应与下面的示例输出类似:

    {
      "clientId": "<client-id>",
      "clientSecretUrl": "<clientSecretUrl>",
      "id": "/subscriptions/<subscriptionid>/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myKubeletIdentity", 
      "location": "chinaeast2",
      "name": "myKubeletIdentity",
      "principalId": "<principal-id>",
      "resourceGroup": "myResourceGroup",                       
      "tags": {},
      "tenantId": "<tenant-id>",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    

使用用户分配的 kubelet 标识创建群集

现在,可以使用现有标识来创建 AKS 群集。 请确保通过包括 assign-identity 参数和 kubelet 托管标识(使用 assign-kubelet-identity 参数)为控制平面提供托管标识的资源 ID。

  • 使用 az aks create 命令创建具有现有标识的 AKS 群集。

    az aks create \
        --resource-group myResourceGroup \
        --name myManagedCluster \
        --network-plugin azure \
        --vnet-subnet-id <subnet-id> \
        --dns-service-ip 10.2.0.10 \
        --service-cidr 10.2.0.0/24 \
        --enable-managed-identity \
        --assign-identity <identity-resource-id> \
        --assign-kubelet-identity <kubelet-identity-resource-id>
    

    使用你自己的 kubelet 托管标识成功创建 AKS 群集后,应会显示类似于以下示例输出的信息:

      "identity": {
        "principalId": null,
        "tenantId": null,
        "type": "UserAssigned",
        "userAssignedIdentities": {
          "/subscriptions/<subscriptionid>/resourcegroups/resourcegroups/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity": {
            "clientId": "<client-id>",
            "principalId": "<principal-id>"
          }
        }
      },
      "identityProfile": {
        "kubeletidentity": {
          "clientId": "<client-id>",
          "objectId": "<object-id>",
          "resourceId": "/subscriptions/<subscriptionid>/resourcegroups/resourcegroups/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myKubeletIdentity"
        }
      },
    

使用 kubelet 标识更新现有群集

警告

更新 kubelet 托管标识会升级节点池,这会导致 AKS 群集停机,因为节点池中的节点将被封锁/排空,然后重置映像。

注意

如果群集使用 --attach-acr 从 Azure 容器注册表的映像中进行拉取,则需要在更新集群后运行 az aks update --resource-group myResourceGroup --name myAKSCluster --attach-acr <ACR Resource ID>,以便让新建的用于托管标识的 kubelet 能够获得从 ACR 进行拉取的权限。 否则,升级后将无法从 ACR 进行拉取。

获取 AKS 群集的当前控制平面托管标识

  1. 使用 az aks show 命令确认 AKS 群集是否在使用用户分配的托管标识。

    az aks show -g <RGName> -n <ClusterName> --query "servicePrincipalProfile"
    

    如果群集使用托管标识,则输出会显示 clientId,其值为 msi。 使用服务主体的群集会显示一个对象 ID。 例如:

    {
      "clientId": "msi"
    }
    
  2. 确认群集正在使用托管标识后,可使用 az aks show 命令查找托管标识的资源 ID。

    az aks show -g <RGName> -n <ClusterName> --query "identity"
    

    对于用户分配的托管标识,输出应类似于以下示例输出:

    {
      "principalId": null,
      "tenantId": null,
      "type": "UserAssigned",
      "userAssignedIdentities": <identity-resource-id>
          "clientId": "<client-id>",
          "principalId": "<principal-id>"
    },
    

使用 kubelet 标识更新群集

  1. 如果你没有 kubelet 托管标识,请使用 az identity create 命令创建一个。

    az identity create --name myKubeletIdentity --resource-group myResourceGroup
    

    输出应与下面的示例输出类似:

    {
      "clientId": "<client-id>",
      "clientSecretUrl": "<clientSecretUrl>",
      "id": "/subscriptions/<subscriptionid>/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myKubeletIdentity",
      "location": "chinaeast2",
      "name": "myKubeletIdentity",
      "principalId": "<principal-id>",
      "resourceGroup": "myResourceGroup",                       
      "tags": {},
      "tenantId": "<tenant-id>",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    
  2. 使用 az aks update 命令更新具有现有标识的群集。 请确保通过包括 assign-identity 参数和 assign-kubelet-identity 参数的 kubelet 托管标识为控制平面提供托管标识的资源 ID。

    az aks update \
        --resource-group myResourceGroup \
        --name myManagedCluster \
        --enable-managed-identity \
        --assign-identity <identity-resource-id> \
        --assign-kubelet-identity <kubelet-identity-resource-id>
    

    使用你自己的 kubelet 托管标识成功更新 AKS 群集后,应会显示类似于以下示例输出的信息:

      "identity": {
        "principalId": null,
        "tenantId": null,
        "type": "UserAssigned",
        "userAssignedIdentities": {
          "/subscriptions/<subscriptionid>/resourcegroups/resourcegroups/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity": {
            "clientId": "<client-id>",
            "principalId": "<principal-id>"
          }
        }
      },
      "identityProfile": {
        "kubeletidentity": {
          "clientId": "<client-id>",
          "objectId": "<object-id>",
          "resourceId": "/subscriptions/<subscriptionid>/resourcegroups/resourcegroups/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myKubeletIdentity"
        }
      },