You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用用户分配托管身份编程认证AKS与Azure AD报未授权错误排查

问题根因

运行代码返回401未授权是四个配置错误共同导致的:

  • 调用IMDS元数据接口获取AKS访问令牌时,resource参数错误添加了.default后缀:你调用的http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01是Azure AD v1.0令牌接口,仅支持传入纯资源URI/应用ID作为resource值,.default是Azure AD v2.0接口的scope语法,v1接口无法识别,最终返回的令牌受众(aud)和AKS集群要求完全不匹配。
  • AKS令牌受众配置与集群能力不匹配:你传入的6dae42f8-4368-4678-94ff-3960e28e3630是老版本未开启Azure RBAC的AKS全球版服务端应用ID,如果你集群开启了Azure RBAC for AKS,合法受众应为https://aks.azure.com;如果是Azure中国区AKS,对应受众还需要替换为中国区专属值。
  • 手动修改kubeconfig authProvider字段的逻辑存在兼容问题:部分版本的C# Kubernetes客户端会在发起请求前自动触发内置的azure auth provider刷新令牌逻辑,直接覆盖你手动写入的access-token值,最终还是用错误配置的令牌发起请求。
  • 权限继承逻辑认知偏差:你给用户分配托管身份授予的资源组/订阅级Owner角色属于Azure管理平面权限,不会自动继承为AKS集群的数据平面访问权限,需要单独在集群作用域配置对应RBAC规则。
排查修复步骤
  • 第一步:校验RBAC权限配置
    先在VM本地通过Azure CLI验证身份权限是否正常:
    1. 执行az login --identity -u <你的用户分配托管身份clientID>登录
    2. 执行az aks get-credentials -g <AKS资源组名> -n <AKS集群名>拉取普通用户kubeconfig
    3. 执行kubectl get ns验证是否能正常访问集群,如果这一步也报401,说明是RBAC配置问题,和代码无关:
      • 若集群开启Azure RBAC for AKS,需要在AKS集群资源作用域给托管身份授予Azure Kubernetes Service Cluster User或者更高的数据平面角色
      • 若集群使用原生Kubernetes RBAC,需要在集群内创建对应ClusterRoleBinding,将权限绑定到托管身份对应的Azure AD服务主体
  • 第二步:修正令牌获取逻辑
    统一使用DefaultAzureCredential获取两类令牌,不要手动调用IMDS接口:
    • 访问Azure管理平面拉取kubeconfig的令牌scope固定为https://management.azure.com/.default
    • 访问AKS数据平面的令牌scope根据集群配置选择:开启Azure RBAC的全球版集群用https://aks.azure.com/.default,未开启Azure RBAC的老版本全球版集群用6dae42f8-4368-4678-94ff-3960e28e3630/.default
  • 第三步:绕开Kubernetes客户端内置的Azure认证逻辑
    不要手动修改kubeconfig里的authProvider字段,通过自定义HTTP请求管道的方式自动注入有效令牌,避免内置逻辑覆盖令牌配置。
修复后可运行代码示例
using System.Net.Http.Headers;
using Azure.Core;
using Azure.Identity;
using k8s;
using k8s.Models;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Rest;

// 基础配置项
string userAssignedClientId = "0f2a4a25-e37f-4aba-942a-5c58f39eb136";
string subscriptionId = "替换为你的订阅ID";
string resourceGroupName = "替换为AKS所在资源组名";
string aksClusterName = "替换为你的AKS集群名";
// 按集群实际配置替换AKS数据平面受众:
// 1. 开启Azure RBAC的全球版AKS: https://aks.azure.com
// 2. 未开Azure RBAC的老版本全球版AKS: 6dae42f8-4368-4678-94ff-3960e28e3630
// 3. 开启Azure RBAC的中国区AKS: https://aks.azure.cn
string aksAudiance = "https://aks.azure.com";
string armScope = "https://management.azure.com/.default";

// 初始化托管身份凭证
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions 
{ 
    ManagedIdentityClientId = userAssignedClientId 
});

// 获取ARM令牌,拉取用户维度kubeconfig
var armToken = credential.GetToken(new TokenRequestContext(new[] { armScope })).Token;
var armTokenCred = new TokenCredentials(armToken);
var azureCred = new Microsoft.Azure.Management.ResourceManager.Fluent.Authentication.AzureCredentials(
    armTokenCred, 
    armTokenCred, 
    null, 
    AzureEnvironment.AzureGlobalCloud);
var azureClient = Azure.Authenticate(azureCred).WithSubscription(subscriptionId);
var kubeConfigBytes = azureClient.KubernetesClusters.GetUserKubeConfigContents(resourceGroupName, aksClusterName);

// 加载kubeconfig,清空内置认证配置避免冲突
var kubeConfigRaw = KubernetesClientConfiguration.LoadKubeConfig(new MemoryStream(kubeConfigBytes));
var k8sConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubeConfigRaw);
k8sConfig.AccessToken = null;
k8sConfig.Username = null;
k8sConfig.Password = null;

// 注入自定义令牌处理器,自动刷新AKS访问令牌
k8sConfig.CreateHttpClientHandler = () =>
{
    var rootHandler = new HttpClientHandler();
    return new AksTokenInjectHandler(credential, aksAudiance) { InnerHandler = rootHandler };
};

// 初始化客户端执行测试操作
var k8sClient = new Kubernetes(k8sConfig);
var nsList = k8sClient.CoreV1.ListNamespace();
foreach (var ns in nsList.Items)
{
    Console.WriteLine($"命名空间: {ns.Metadata.Name}");
    var podList = k8sClient.CoreV1.ListNamespacedPod(ns.Metadata.Name);
    foreach (var pod in podList.Items)
    {
        Console.WriteLine($"  Pod: {pod.Metadata.Name}");
    }
}

/// <summary>
/// AKS令牌自动注入处理器
/// </summary>
internal class AksTokenInjectHandler : DelegatingHandler
{
    private readonly TokenCredential _tokenCredential;
    private readonly string[] _aksScopes;

    public AksTokenInjectHandler(TokenCredential credential, string aksAudience)
    {
        _tokenCredential = credential;
        _aksScopes = new[] { $"{aksAudience}/.default" };
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var tokenRes = await _tokenCredential.GetTokenAsync(new TokenRequestContext(_aksScopes), cancellationToken);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenRes.Token);
        return await base.SendAsync(request, cancellationToken);
    }
}
额外校验点

拿到AKS访问令牌后,可以解码JWT的payload部分,确认aud字段值和你配置的AKS受众完全一致,如果不一致说明scope配置仍然错误。

内容的提问来源于stack exchange,提问作者Ching Kuo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 11:06:29