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

Azure Kubernetes 服务 (AKS) 群集需要标识才能访问负载均衡器和托管磁盘等 Azure 资源。 此标识可以是托管标识或服务主体。 默认情况下,创建 AKS 群集时会自动创建系统分配的托管标识。 标识由 Azure 平台托管,无需预配或轮换任何机密。 有关 Azure AD 中的托管标识的详细信息,请参阅 Azure 资源的托管标识

若要使用服务主体,你必须创建一个服务主体,因为 AKS 不会自动创建服务主体。 使用服务主体的群集最终会过期,必须续订服务主体才能让群集保持正常运行。 管理服务主体会增加复杂性,这也是托管标识使用起来更简单的原因。 服务主体和托管标识适用相同的权限要求。

托管标识本质上是服务主体的包装器,这使其更易于管理。 托管标识使用基于证书的身份验证,每个托管标识凭据的有效期为 90 天,在 45 天后滚动更新。 AKS 使用系统分配和用户分配的托管标识类型,这些标识是不可变的。

先决条件

Azure CLI 2.23.0 或更高版本。 运行 az --version 即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

限制

  • 不支持移动或迁移启用了托管标识的群集的租户。
  • 如果群集启用了 aad-pod-identity,节点托管标识 (NMI) pod 将修改节点的 iptable,以拦截对 Azure 实例元数据终结点的调用。 此配置意味着对元数据终结点发出的任何请求都将被 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。 有关详细信息,请参阅禁用特定 pod 或应用程序的 aad-pod-identity。 若要配置例外情况,请安装 mic-exception YAML

托管标识摘要

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

标识 名称 使用案例 默认权限 自带标识
控制面板 AKS 群集名称 由 AKS 控制平面组件用于管理群集资源,包括入口负载均衡器和 AKS 管理的公共 IP、群集自动缩放程序、Azure 磁盘和文件 CSI 驱动程序 节点资源组的参与者角色 支持
Kubelet AKS Cluster Name-agentpool 向 Azure 容器注册表 (ACR) 进行身份验证 NA(对于 kubernetes v1.15+) 支持
加载项 AzureNPM 无需标识 不可用
加载项 AzureCNI 网络监视 无需标识 不可用
加载项 azure-policy (gatekeeper) 无需标识 不可用
加载项 azure-policy 无需标识 不可用
加载项 Calico 无需标识 不可用
加载项 仪表板 无需标识 不可用
加载项 HTTPApplicationRouting 管理所需的网络资源 节点资源组的读取者角色,DNS 区域的参与者角色
加载项 入口应用程序网关 管理所需的网络资源 节点资源组的参与者角色
加载项 omsagent 用于将 AKS 指标发送到 Azure Monitor “监视指标发布者”角色
加载项 Virtual-Node (ACIConnector) 管理 Azure 容器实例 (ACI) 所需的网络资源 节点资源组的参与者角色
OSS 项目 aad-pod-identity 通过 Microsoft Azure Active Directory (AAD) 使应用程序可安全访问云资源 NA https://github.com/Azure/aad-pod-identity#role-assignment 处提供了授予权限的步骤。

使用托管标识创建 AKS 群集

注意

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

可以运行以下 CLI 命令使用系统分配的托管标识来创建 AKS 群集。

首先,创建 Azure 资源组:

# Create an Azure resource group
az group create --name myResourceGroup --location chinaeast2

然后,创建 AKS 群集:

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

创建群集后,你便可以将应用程序工作负荷部署到新群集中,并与之交互,就像与基于服务主体的 AKS 群集交互一样。

最后,获取用于访问群集的凭据:

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

将 AKS 群集更新为使用托管标识

若要将当前使用服务主体的 AKS 群集更新为使用系统分配的托管标识,请运行以下 CLI 命令。

az aks update -g <RGName> -n <AKSName> --enable-managed-identity

注意

仅当存在要使用的实际 VHD 更新时,更新才起作用。 如果你正在运行最新的 VHD,需要等到下一个 VHD 可用才能执行更新。

注意

更新群集的控制平面和加载项 Pod 后,它们将使用托管标识,但 kubelet 将继续使用服务主体,直到升级代理池。 请在节点上执行 az aks nodepool upgrade --node-image-only 以完成对托管标识的更新。

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

Azure CLI 将会确保加载项的权限在迁移后得到正确设置,如果未使用 Azure CLI 来执行迁移操作,则需要自行处理加载项标识的权限。 下面是一个使用 Azure 资源管理器模板的示例。

警告

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

为控制平面标识添加角色分配

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

注意

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

获取控制平面标识的主体 ID

可以通过运行以下命令来查找现有标识的主体 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 --assignee <control-plane-identity-principal-id> --role "Contributor" --scope "<custom-resource-group-resource-id>"

示例:

az role assignment create --assignee 22222222-2222-2222-2222-222222222222 --role "Contributor" --scope "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/custom-resource-group"

对于默认工作器节点资源组外部由用户分配的 kubelet 标识,需要对 kubelet 标识分配 Managed Identity Operator

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

示例:

az role assignment create --assignee 22222222-2222-2222-2222-222222222222 --role "Managed Identity Operator" --scope "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myKubeletIdentity"

注意

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

自带控制平面托管标识

使用自定义控制平面托管标识,可以在创建群集之前向现有标识授予访问权限。 此功能适用于多种场景,例如将自定义 VNET 或 outboundType UDR 与预先创建的托管标识结合使用。

注意

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

如果你没有托管标识,应运行 az identity 命令创建一个。

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 aks create \
    --resource-group myResourceGroup \
    --name myManagedCluster \
    --network-plugin azure \
    --vnet-subnet-id <subnet-id> \
    --docker-bridge-address 172.17.0.1/16 \
    --dns-service-ip 10.2.0.10 \
    --service-cidr 10.2.0.0/24 \
    --enable-managed-identity \
    --assign-identity <identity-resource-id>

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

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

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

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

先决条件

  • 已安装 Azure CLI 2.26.0 或更高版本。 运行 az --version 即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

限制

  • 仅适用于用户分配的托管群集。
  • 目前不支持 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 托管标识,可运行以下 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 提供控制平面标识资源 ID,通过 assign-kubelet-identity 提供 kubelet 托管标识:

az aks create \
    --resource-group myResourceGroup \
    --name myManagedCluster \
    --network-plugin azure \
    --vnet-subnet-id <subnet-id> \
    --docker-bridge-address 172.17.0.1/16 \
    --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 标识更新现有群集

使用现有标识更新现有 AKS 群集上的 kubelet 标识。

警告

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

注意

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

请确保 CLI 版本是 2.37.0 或更高版本

# Check the version of Azure CLI modules 
az version

# Upgrade the version to make sure it is 2.37.0 or later
az upgrade

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

使用以下 CLI 命令确认 AKS 群集是否在使用用户分配的控制平面标识:

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

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

{
  "clientId": "msi"
}

确认群集正在使用托管标识后,可运行以下命令查找控制平面标识的资源 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 标识更新群集

如果你没有 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"
}

现在,可以使用以下命令更新具有现有标识的群集。 通过 assign-identity 提供控制平面标识资源 ID,通过 assign-kubelet-identity 提供 kubelet 托管标识:

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

使用自己的 kubelet 托管标识成功更新的群集应包含以下输出:

  "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"
    }
  },