使用托管标识从本地 Azure 函数查询 Azure SQL 数据库

Query Azure SQL Database from local Azure Function using Managed Identities

我想使用托管身份(即连接到 Visual Studio 的用户的身份,而不是提供用户 ID 和密码,从调试中在我的机器上执行的 Azure 函数查询 Azure SQL 数据库在我的连接字符串中)。

我关注 this tutorial Microsoft 文档,所以我的 Azure SQL 服务器有一个 AD 用户作为管理员,这允许我将权限 (db_datareader) 授予我创建的 Azure AD 组包含我的 Azure Function Identity 和我的用户(还有我部署在 Azure 中的 Function App)。

如果我在 Azure 中部署并 运行 我的 Azure 函数,它能够查询我的数据库并且一切正常。但是当我在本地 运行 我的 Azure Function 时,出现以下错误:

Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'.

我的函数代码如下:

    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "test")] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");


        using (var connection = new SqlConnection(Environment.GetEnvironmentVariable("sqlConnectionString")))
        {
            connection.AccessToken = await (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net");
            log.LogInformation($"Access token : {connection.AccessToken}");
            try
            {
                await connection.OpenAsync();
                var rows = await connection.QueryAsync<Test>("select top 10 * from TestTable");
                return new OkObjectResult(rows);
            }
            catch (Exception e)
            {
                throw e;
            }

        }
    }

代码正确检索到令牌,错误发生在第 await connection.OpenAsync() 行。

如果我在 Azure Data Studio 中打开数据库的用户与连接到 Visual Studio 的用户相同(该用户是具有数据库权限的 AD 组成员),我可以连接并查询数据库没有任何问题。

这是已知问题还是我遗漏了什么?

您本地机器的 IP 地址是否在白名单中?

https://docs.microsoft.com/en-us/azure/sql-database/sql-database-firewall-configure

在尝试了您的具体方案后,我测试了很多方法来尝试让它在本地工作。这没有用,给出与您收到的相同的错误消息。

当出现可能的解决方案时,我与一些人讨论过。我测试了一下:有效!

我的主要问题是我的订阅(和我的用户)是 Microsoft 帐户 (Outlook)。因此,您需要在 GetAccessTokenAsync() 调用中指定 tenantId

显然,对于托管身份,您不必指定 tenantId。对于用户,明确指定它是个好主意。如果是个人 MS 帐户,则必须指定它。

我的代码(有点):

var tokenProvider = new AzureServiceTokenProvider();

using (var connection = new SqlConnection(CONNECTIONSTRING))
using (var command = new SqlCommand(QUERY, connection))
{
    connection.AccessToken = await tokenProvider.GetAccessTokenAsync("https://database.windows.net/", "<YOUR_TENANT_ID>");

    await connection.OpenAsync();
    var result = (await command.ExecuteScalarAsync()).ToString();

    return new OkObjectResult(result);
}

此解决方案已经过测试,在指定 tenantId(或目录 ID,租户的 GUID)和 'onmicrosoft'-名称 (xxx.onmicrosoft.com) 时均有效。