在 Azure Kubernetes 服务中使用 Microsoft Entra Pod 托管标识(预览版)

Microsoft Entra Pod 托管标识使用 Kubernetes 基元将 Azure 资源托管标识和 Microsoft Entra ID 中的标识与 Pod 关联到一起。 管理员创建 Kubernetes 基元形式的标识和绑定,使 Pod 能够以标识提供者的身份访问依赖于 Microsoft Entra ID 的 Azure 资源。

重要

建议查看 Microsoft Entra 工作负载 ID。 此身份验证方法将替代 Pod 托管标识(预览版),后者与 Kubernetes 本机功能集成,以便代表应用程序与任何外部标识提供者联合。

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

若要禁用 AKS 托管加载项,请使用以下命令:az feature unregister --namespace "Microsoft.ContainerService" --name "EnablePodIdentityPreview"

准备阶段

必须安装 Azure CLI 2.20.0 或更高版本。

限制

  • 对于一个群集,最多允许 200 个 Pod 托管标识。
  • 对于一个群集,最多允许 200 个 Pod 托管标识异常。
  • 只能在 Linux 节点池中使用 Pod 托管标识。
  • 只有虚拟机规模集支持的群集才支持此功能。

安装 aks-preview Azure CLI 扩展

重要

AKS 预览功能是可选择启用的自助功能。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

若要安装 aks-preview 扩展,请运行以下命令:

az extension add --name aks-preview

运行以下命令以更新到已发布的最新扩展版本:

az extension update --name aks-preview

注册“EnablePodIdentityPreview”功能标志

使用 EnablePodIdentityPreview 命令注册 EnablePodIdentityPreview 功能标志,如以下示例所示:

az feature register --namespace "Microsoft.ContainerService" --name "EnablePodIdentityPreview"

状态显示为“已注册”需要几分钟时间。 使用 az feature show 命令验证注册状态:

az feature show --namespace "Microsoft.ContainerService" --name "EnablePodIdentityPreview"

当状态反映为“已注册”时,使用 az provider register 命令刷新 Microsoft.ContainerService 资源提供程序的注册:

az provider register --namespace Microsoft.ContainerService

操作模式选项

Microsoft Entra Pod 托管标识支持两种操作模式:

  • 标准模式:在此模式下,将以下两个组件部署到 AKS 群集:
    • 托管标识控制器 (MIC):MIC 是一种 Kubernetes 控制器,通过 Kubernetes API 服务器监视对 Pod、AzureIdentityAzureIdentityBinding 所做的更改。 检测到相关更改时,MIC 会根据需要添加或删除 AzureAssignedIdentity。 具体而言,如果计划了 Pod,MIC 会将 Azure 上的托管标识分配给节点池在创建阶段使用的基础虚拟机规模集。 删除所有使用该标识的 Pod 时,MIC 会从节点池的虚拟机规模集中删除标识,除非其他 Pod 使用相同的托管标识。 创建或删除 AzureIdentity 或 AzureIdentityBinding 时,MIC 会执行类似的操作。
    • 节点托管标识 (NMI):NMI 是在 AKS 群集中每个节点上作为 DaemonSet 运行的 Pod。 NMI 截获每个节点上对 Azure 实例元数据服务的安全令牌请求,将这些请求重定向到自身并验证 Pod 是否有权访问它为其请求令牌的标识,并代表应用程序从 Microsoft Entra 租户中提取令牌。
  • 托管模式:此模式仅提供 NMI。 通过 AKS 群集加载项安装时,Azure 管理创建 Kubernetes 基元(AzureIdentity 和 AzureIdentityBinding)和标识分配,以响应用户的 CLI 命令。 否则,如果通过 Helm 图表安装,则标识需要由用户手动分配和管理。 有关详细信息,请参阅托管模式下的 Pod 标识

安装指南中所示通过 Helm 图表或 YAML 清单安装 Microsoft Entra Pod 托管标识时,可以在 standardmanaged 模式之间进行选择。 如果决定改为如本文所述使用 AKS 群集加载项安装 Microsoft Entra Pod 托管标识,安装程序将使用 managed 模式。

使用 Azure 容器网络接口 (CNI) 创建 AKS 群集

注意

这是建议的默认配置

创建使用 Azure CNI 并已启用 Pod 托管标识的 AKS 群集。 以下命令使用 az group create 创建名为 myResourceGroup 的资源组,并使用 az aks create 命令在 myResourceGroup 资源组中创建名为 myAKSCluster 的 AKS 群集。

az group create --name myResourceGroup --location chinaeast2
az aks create -g myResourceGroup -n myAKSCluster --enable-pod-identity --network-plugin azure

使用 az aks get-credentials 登录到 AKS 群集。 此命令还会在开发计算机上下载并配置 kubectl 客户端证书。

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

注意

在 AKS 群集上启用 Pod 托管标识时,会将名为 aks-addon-exception 的 AzurePodIdentityException 添加到 kube-system 命名空间。 AzurePodIdentityException 允许带有特定标签的 Pod 访问 Azure 实例元数据服务 (IMDS) 终结点,而不会被 NMI 服务器拦截。 aks-addon-exception 允许 AKS 第一方加载项(例如 Microsoft Entra Pod 托管标识)正常运行,而无需手动配置 AzurePodIdentityException。 (可选)可以使用 az aks pod-identity exception addaz aks pod-identity exception deleteaz aks pod-identity exception updatekubectl 添加、删除和更新 AzurePodIdentityException。

更新使用 Azure CNI 的现有 AKS 群集

更新使用 Azure CNI 的现有 AKS 群集以包含 Pod 托管标识。

az aks update -g $MY_RESOURCE_GROUP -n $MY_CLUSTER --enable-pod-identity

将 Kubenet 网络插件与 Microsoft Entra Pod 托管标识配合使用

重要

出于安全考虑,不建议采用在群集中通过 Kubenet 运行 Microsoft Entra Pod 托管标识这种配置。 默认 Kubenet 配置无法阻止 ARP 欺骗,Pod 可以利用该欺骗充当另一个 Pod,并获取对非预期标识的访问权限。 在使用 Kubenet 的群集中启用 Microsoft Entra Pod 托管标识之前,请遵循缓解步骤并配置策略。

缓解

为了缓解群集级别的漏洞,可以使用 Azure 内置策略“Kubernetes 群集容器应仅使用允许的功能”来限制 CAP_NET_RAW 攻击。

将 NET_RAW 添加到“需要删除功能”

image

如果没有使用 Azure Policy,可以将 OpenPolicyAgent 许可控制器与验证 Webhook 的 Gatekeeper 一起使用。 如果已在群集中安装了 Gatekeeper,请添加 K8sPSPCapabilities 类型的 ConstraintTemplate:

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/capabilities/template.yaml

添加一个模板,以通过 NET_RAW 功能限制 Pod 繁生:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: prevent-net-raw
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces:
      - "kube-system"
  parameters:
    requiredDropCapabilities: ["NET_RAW"]

创建使用 Kubenet 网络插件的 AKS 群集

创建一个使用 Kubenet 网络插件并已启用 Pod 托管标识的 AKS 群集。

az aks create -g $MY_RESOURCE_GROUP -n $MY_CLUSTER --enable-pod-identity --enable-pod-identity-with-kubenet

更新使用 Kubenet 网络插件的现有 AKS 群集

更新使用 Kubenet 网络插件的现有 AKS 群集以包含 Pod 托管标识。

az aks update -g $MY_RESOURCE_GROUP -n $MY_CLUSTER --enable-pod-identity --enable-pod-identity-with-kubenet

创建标识

重要

你必须对订阅拥有相关权限(例如所有者)才能创建标识。

使用 az identity create 创建演示 Pod 使用的标识,并设置 IDENTITY_CLIENT_ID 和 IDENTITY_RESOURCE_ID 变量。

az group create --name myIdentityResourceGroup --location chinaeast2
export IDENTITY_RESOURCE_GROUP="myIdentityResourceGroup"
export IDENTITY_NAME="application-identity"
az identity create --resource-group ${IDENTITY_RESOURCE_GROUP} --name ${IDENTITY_NAME}
export IDENTITY_CLIENT_ID="$(az identity show -g ${IDENTITY_RESOURCE_GROUP} -n ${IDENTITY_NAME} --query clientId -otsv)"
export IDENTITY_RESOURCE_ID="$(az identity show -g ${IDENTITY_RESOURCE_GROUP} -n ${IDENTITY_NAME} --query id -otsv)"

为托管标识分配权限

需要向要分配给 Pod 的托管标识授予与它将采取的操作一致的权限。

若要运行演示,IDENTITY_CLIENT_ID 托管标识必须在包含 AKS 群集虚拟机规模集的资源组中拥有“虚拟机参与者”权限。

# Obtain the name of the resource group containing the Virtual Machine Scale set of your AKS cluster, commonly called the node resource group
NODE_GROUP=$(az aks show -g myResourceGroup -n myAKSCluster --query nodeResourceGroup -o tsv)

# Obtain the id of the node resource group 
NODES_RESOURCE_ID=$(az group show -n $NODE_GROUP -o tsv --query "id")

# Create a role assignment granting your managed identity permissions on the node resource group
az role assignment create --role "Virtual Machine Contributor" --assignee "$IDENTITY_CLIENT_ID" --scope $NODES_RESOURCE_ID

创建 Pod 标识

使用 az aks pod-identity add 创建群集的 Pod 托管标识。

export POD_IDENTITY_NAME="my-pod-identity"
export POD_IDENTITY_NAMESPACE="my-app"
az aks pod-identity add --resource-group myResourceGroup --cluster-name myAKSCluster --namespace ${POD_IDENTITY_NAMESPACE}  --name ${POD_IDENTITY_NAME} --identity-resource-id ${IDENTITY_RESOURCE_ID}

注意

“POD_IDENTITY_NAME”必须是有效的 DNS 子域名称,如 RFC 1123 中定义的那样。

注意

使用 pod-identity add 分配 Pod 托管标识时,Azure CLI 尝试通过 Pod 托管标识 (IDENTITY_RESOURCE_ID) 向群集标识授予“托管标识操作员”角色。

Azure 将在群集中创建一个表示 Azure 中标识的 AzureIdentity 资源,以及一个将 AzureIdentity 连接到选择器的 AzureIdentityBinding 资源。 你可以通过以下方式查看这些资源

kubectl get azureidentity -n $POD_IDENTITY_NAMESPACE
kubectl get azureidentitybinding -n $POD_IDENTITY_NAMESPACE

运行示例应用程序

要使某个 Pod 能够使用 Microsoft Entra Pod 托管标识,该 Pod 需要一个 aadpodidbinding 标签,其值与 AzureIdentityBinding 中的选择器相匹配。 默认情况下,选择器将匹配 Pod 托管标识的名称,但也可在调用 az aks pod-identity add 时使用 --binding-selector 选项进行设置。

要使用 Microsoft Entra Pod 托管标识运行示例应用程序,请创建包含以下内容的 demo.yaml 文件。 请将 POD_IDENTITY_NAMEIDENTITY_CLIENT_IDIDENTITY_RESOURCE_GROUP 替换为前面步骤中使用的值。 请将 SUBSCRIPTION_ID 替换为你的订阅 ID。

注意

在前面的步骤中,你已创建 POD_IDENTITY_NAMEIDENTITY_CLIENT_IDIDENTITY_RESOURCE_GROUP 变量。 可以使用诸如 echo 的命令来显示你为变量设置的值(例如 echo $POD_IDENTITY_NAME)。

apiVersion: v1
kind: Pod
metadata:
  name: demo
  labels:
    aadpodidbinding: $POD_IDENTITY_NAME
spec:
  containers:
  - name: demo
    image: mcr.azk8s.cn/oss/azure/aad-pod-identity/demo:v1.6.3
    args:
      - --subscriptionid=$SUBSCRIPTION_ID
      - --clientid=$IDENTITY_CLIENT_ID
      - --resourcegroup=$IDENTITY_RESOURCE_GROUP
    env:
      - name: MY_POD_NAME
        valueFrom:
          fieldRef:
            fieldPath: metadata.name
      - name: MY_POD_NAMESPACE
        valueFrom:
          fieldRef:
            fieldPath: metadata.namespace
      - name: MY_POD_IP
        valueFrom:
          fieldRef:
            fieldPath: status.podIP
  nodeSelector:
    kubernetes.io/os: linux

请注意,Pod 定义包含一个 aadpodidbinding 标签,其值与你在前一个步骤中运行 az aks pod-identity add 时使用的 Pod 托管标识的名称相匹配。

使用 kubectl applydemo.yaml 部署到 Pod 托管标识所在的同一命名空间:

kubectl apply -f demo.yaml --namespace $POD_IDENTITY_NAMESPACE

使用 kubectl logs 确认示例应用程序是否成功运行。

kubectl logs demo --follow --namespace $POD_IDENTITY_NAMESPACE

确认日志中是否显示已成功获取令牌并且 GET 操作成功。

...
successfully doARMOperations vm count 0
successfully acquired a token using the MSI, msiEndpoint(http://169.254.169.254/metadata/identity/oauth2/token)
successfully acquired a token, userAssignedID MSI, msiEndpoint(http://169.254.169.254/metadata/identity/oauth2/token) clientID(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
successfully made GET on instance metadata
...

运行具有多个标识的应用程序

要使应用程序能够使用多个标识,请在创建 Pod 标识时将 --binding-selector 设置为同一选择器。

az aks pod-identity add --resource-group myResourceGroup --cluster-name myAKSCluster --namespace ${POD_IDENTITY_NAMESPACE}  --name ${POD_IDENTITY_NAME_1} --identity-resource-id ${IDENTITY_RESOURCE_ID_1} --binding-selector myMultiIdentitySelector
az aks pod-identity add --resource-group myResourceGroup --cluster-name myAKSCluster --namespace ${POD_IDENTITY_NAMESPACE}  --name ${POD_IDENTITY_NAME_2} --identity-resource-id ${IDENTITY_RESOURCE_ID_2} --binding-selector myMultiIdentitySelector

然后将 Pod YAML 中的 aadpodidbinding 字段设置为指定的绑定选择器。

apiVersion: v1
kind: Pod
metadata:
  name: demo
  labels:
    aadpodidbinding: myMultiIdentitySelector
...

在现有群集上禁用 Pod 托管标识

要在现有群集上禁用 Pod 托管标识,请从群集中移除 Pod 托管标识。 然后在群集上禁用该功能。

az aks pod-identity delete --name ${POD_IDENTITY_NAME} --namespace ${POD_IDENTITY_NAMESPACE} --resource-group myResourceGroup --cluster-name myAKSCluster
az aks update --resource-group myResourceGroup --name myAKSCluster --disable-pod-identity

清理

要从群集中移除 Microsoft Entra Pod 托管标识,请从群集中移除示例应用程序和 Pod 托管标识。 然后删除群集标识的标识和角色分配。

kubectl delete pod demo --namespace $POD_IDENTITY_NAMESPACE
az aks pod-identity delete --name ${POD_IDENTITY_NAME} --namespace ${POD_IDENTITY_NAMESPACE} --resource-group myResourceGroup --cluster-name myAKSCluster
az identity delete -g ${IDENTITY_RESOURCE_GROUP} -n ${IDENTITY_NAME}
az role assignment delete --role "Managed Identity Operator" --assignee "$IDENTITY_CLIENT_ID" --scope "$IDENTITY_RESOURCE_ID"

后续步骤

有关托管标识的详细信息,请参阅 Azure 资源的托管标识