【问题标题】:.NetCore 2.2 API fails to get token from AAD when using User Assigned Identity.NetCore 2.2 API 在使用用户分配的身份时无法从 AAD 获取令牌
【发布时间】:2023-03-08 04:44:01
【问题描述】:

当使用用户分配的托管标识时,我们无法从 Azure 应用服务查询 azure 中的 sql 数据库(如果我们使用系统分配的托管标识,它可以正常工作)

该应用程序是一个 .net core 2.2 web api 应用程序。

我们为 Azure 应用服务设置了用户分配的身份。

已使用以下命令将此身份设置为 ad sql 管理员:

az sql server ad-admin create --resource-group iactests --server iactestsql --object-id -u iactestmanagedIdentity

令牌是这样生成的:

services.AddDbContext<SchoolContext>(options => options.UseSqlServer(new 
SqlConnection
        {
            ConnectionString = configuration.GetConnectionString("SchoolContext"),
            AccessToken = isDevelopmentEnvironment ? null : new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net/").Result
        }), ServiceLifetime.Scoped);

这是我们得到的错误:

    Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://database.windows.net/, Authority: . Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://database.windows.net/, Authority: . Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. MSI ResponseCode: BadRequest, Response: 
Parameters: Connection String: [No connection string specified], Resource: https://database.windows.net/, Authority: . Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Visual Studio Token provider file not found at "D:\local\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json"
Parameters: Connection String: [No connection string specified], Resource: https://database.windows.net/, Authority: . Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. 'az' is not recognized as an internal or external command,
operable program or batch file.


at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAuthResultAsyncImpl(String authority, String resource, String scope)
at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAuthenticationResultAsync(String resource, String tenantId)
at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAccessTokenAsync(String resource, String tenantId)
--- End of inner exception stack trace ---

如果我们使用系统分配身份并将 sql ad admin 配置为身份,则可以正常工作

有什么想法吗?

提前致谢

【问题讨论】:

    标签: azure azure-active-directory azure-sql-database


    【解决方案1】:

    1.2.0-preview2 release 开始,AppAuthentication 库现在支持为 Azure VM 和应用服务指定用户分配的身份。

    要使用用户分配的身份,您需要设置格式如下的 AppAuthentication 连接字符串:

    RunAs=App;AppId={ClientId of user-assigned identity}
    

    AppAuthentication 连接字符串可以设置为传递给 AzureServiceTokenProvider 构造函数的参数,也可以在 AzureServicesAuthConnectionString 环境变量中指定。有关 AppAuthentication 连接字符串的更多信息,请参阅here

    【讨论】:

    • 感谢@nonik 更新此内容!您应该根据链接的文档添加连接字符串在构造函数或“AzureServicesAuthConnectionString”环境变量中设置的答案。
    【解决方案2】:

    看起来 AzureServiceTokenProvider 不支持用户分配的托管标识,至少目前是这样。 AzureServiceTokenProvder 是本地 HTTP 端点的包装器,为应用程序提供令牌。

    我正在调查此问题,看来您必须向端点提供用户分配的托管身份的 clientId 才能获取令牌。而且 AzureServiceTokenProvider 没有办法做到这一点(至少我能弄清楚)。

    用户分配的托管身份增加了为应用程序拥有多个用户分配的托管身份的能力。因此,获取令牌的 API 需要指定您想要的 MSI、系统分配的 MSI 或 其中一个用户分配的 MSI。 HTTP 端点执行此操作的方式是使用系统分配的 MSI,除非您指定 clientId。

    在任何情况下,您都可以直接点击令牌端点,并提供用户分配的 MSI 的 clientId,如下所示:

    public async Task<String> GetToken(string resource, string clientId = null)
    {
        var endpoint = System.Environment.GetEnvironmentVariable("MSI_ENDPOINT", EnvironmentVariableTarget.Process);
        var secret = System.Environment.GetEnvironmentVariable("MSI_SECRET", EnvironmentVariableTarget.Process);
    
        if (string.IsNullOrEmpty(endpoint))
        {
            throw new InvalidOperationException("MSI_ENDPOINT environment variable not set");
        }
        if (string.IsNullOrEmpty(secret))
        {
            throw new InvalidOperationException("MSI_SECRET environment variable not set");
        }
    
        Uri uri;
        if (clientId == null)
        {
            uri = new Uri($"{endpoint}?resource={resource}&api-version=2017-09-01");
        }
        else
        {
            uri = new Uri($"{endpoint}?resource={resource}&api-version=2017-09-01&clientid={clientId}");
        }
    
        // get token from MSI
        var tokenRequest = new HttpRequestMessage()
        {
            RequestUri = uri,
            Method = HttpMethod.Get
        };
        tokenRequest.Headers.Add("secret", secret);
        var httpClient = new HttpClient();
    
        var response = await httpClient.SendAsync(tokenRequest);
    
        var body = await response.Content.ReadAsStringAsync();
        var result = JObject.Parse(body);
    
        string token = result["access_token"].ToString();
        return token;
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-10
      • 2014-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-23
      相关资源
      最近更新 更多