密码身份验证失败 Azure Function 作为 Azure Database for PostgreSQL 灵活服务器的托管标识

问题描述 投票:0回答:1

我有带有系统标识的 Azure Function、带有 Azure 中标识的 Azure Database for PostgreSQL 灵活服务器。出于测试目的,PosttgreSQL 允许公共访问。

  • 我可以使用

    DefaultAzureCredential
    (az 登录)从我的计算机连接到 PostgreSQL,并将我的电子邮件指定为
    Username
    中的
    NpgsqlConnectionStringBuilder
    ,即使我认为这应该在没有用户名的情况下工作,因为它是依赖其他 AccessToken 和其中的数据。如果我不指定
    Username
    ,它始终会选择计算机上的用户名,而不是来自 Azure 凭据的用户名。但至少我让它与
    Username
    一起工作。

  • 当我使用

    ManagedIdentityCredential
    并将代码部署到该函数时,它找到 PostgreSQL,尝试连接但由于用户名而失败。这是代码和错误消息:

    [Function("TestOpenConnection")]
    public async Task<IActionResult> RunTestOpenConnectionMisc([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, CancellationToken cancellationToken)
    {
        _logger.LogInformation(3009, "C# HTTP trigger TestOpenConnection function processed a request.");
        
        string connectionString = new NpgsqlConnectionStringBuilder
        {
            Host = "my-xyz-pgsql.postgres.database.azure.com",
            Port = 5432,
            Database = "my_test_db",
            SslMode = SslMode.Require,
            // ?? Username
        }.ToString();

        NpgsqlDataSourceBuilder dataSourceBuilder = new(connectionString);

        TimeSpan successRefreshInterval = TimeSpan.FromMinutes(55);
        TimeSpan failureRefreshInterval = TimeSpan.FromSeconds(30);

        dataSourceBuilder.UsePeriodicPasswordProvider(async (_, ct)
            => await GetAccessTokenAsync(ct), successRefreshInterval, failureRefreshInterval);

        await using var dataSource = dataSourceBuilder.Build();

        try
        {
            await dataSource.OpenConnectionAsync(cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError(2004, e, "FAILED TO OPEN DATABASE CONNECTION");
            return new BadRequestObjectResult(e);
        }
        
        _logger.LogInformation(3011, "Connection opened successfully");
        return new OkObjectResult("Connection opened successfully");
    }
    
    private async Task<string> GetAccessTokenAsync(CancellationToken cancellationToken)
    {
        ManagedIdentityCredential credential = new();
        string resource = "https://ossrdbms-aad.database.windows.net";
        TokenRequestContext tokenRequestContext = new([$"{resource}/.default"]);
        AccessToken fullToken = await credential.GetTokenAsync(tokenRequestContext, cancellationToken).ConfigureAwait(false);
        return fullToken.Token;
    }

错误:

[Error]   FAILED TO OPEN DATABASE CONNECTION
password authentication failed for user "funct-test-postrgre-xyz"

我已经测试了令牌的获取,它可以工作并获取函数身份的正确访问令牌。我尝试了几种连接方式,但我已经没有主意了:

  • 我尝试使用
    Function name
    作为
    Username
  • 我尝试使用
    Service Principal ObjectId
    作为
    Username
  • 我尝试使用
    Service Principal ApplicationId
    作为
    Username

每次我都会得到:

28P01: password authentication failed for user "name/objectId/applicationId"

我需要在 PostreSQL 端设置其他东西吗?

我执行了以下命令:


-- Create a Role for the Enterprise Application:
CREATE ROLE "00000000-0000-0000-0000-000000000000" WITH LOGIN;

-- Grant Privileges to the Role:
GRANT CONNECT ON DATABASE my_test_db TO "00000000-0000-0000-0000-000000000000";
GRANT USAGE ON SCHEMA public TO "00000000-0000-0000-0000-000000000000";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "00000000-0000-0000-0000-000000000000";

-- Configure Default Privileges (Optional):
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "00000000-0000-0000-0000-000000000000";

如何验证 PostreSQL 是否设置正确?是服务主体 ApplicationId 还是 ObjectId?

postgresql azure-functions azure-managed-identity
1个回答
0
投票

我也遇到了同样的错误。

控制您访问令牌的身份验证过程,使用``

作为参考,请检查此 MS 文档

DefaultAzureCredential
使用所有方法进行身份验证顺序。 如需订购,请查看此MS Document

这个查询对我有用。

SELECT * FROM pgaadauth_create_principal('<identity_name>', false, false);

#This query assigns these access("create User","Assign Superuser", "Assign Admin")

作为参考,请检查此 MS 文档

传递数值

Username = <Identity_name>

我的代码:

  • 我正在使用动态模型作为用户名
    string User = req.Query["User"].FirstOrDefault() ?? Environment.GetEnvironmentVariable("User");
  • 确保您已使用
    Postgresql
  • 中的查询创建用户
using Azure.Core;
using Azure.Identity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Npgsql;
using System.Threading;

namespace FunctionApp5
{
    public class Function
    {
        private readonly ILogger<Function> _logger;

        public Function(ILogger<Function> logger)
        {
            _logger = logger;
        }

        [Function("Function")]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req, CancellationToken cancellationToken)
        {
            _logger.LogInformation(3009, "C# HTTP trigger TestOpenConnection function processed a request.");

            string User = req.Query["User"].FirstOrDefault() ?? Environment.GetEnvironmentVariable("User");

            string connectionString = new NpgsqlConnectionStringBuilder
            {
                Host = "postgre16sep.postgres.database.azure.com",
                Port = 5432,
                Database = "postgres",
                Username = User,
                SslMode = SslMode.Require,
            }.ToString();

            NpgsqlDataSourceBuilder dataSourceBuilder = new (connectionString);

            TimeSpan successRefreshInterval = TimeSpan.FromMinutes(55);
            TimeSpan failureRefreshInterval = TimeSpan.FromSeconds(30);

            dataSourceBuilder.UsePeriodicPasswordProvider(async (_, ct)
                => await GetAccessTokenAsync(ct), successRefreshInterval, failureRefreshInterval);

            await using var dataSource = dataSourceBuilder.Build();

            try
            {
                await dataSource.OpenConnectionAsync(cancellationToken);
            }
            catch (Exception e)
            {
                _logger.LogError(2004, e, "FAILED TO OPEN DATABASE CONNECTION");
                return new BadRequestObjectResult(e.Message);
            }

            _logger.LogInformation(3011, "Connection opened successfully");
            return new OkObjectResult("Connection opened successfully");
        }

        private async Task<string> GetAccessTokenAsync(CancellationToken cancellationToken)
        {
            var credential = new DefaultAzureCredential();
            string resource = "https://ossrdbms-aad.database.windows.net";
            TokenRequestContext tokenRequestContext = new TokenRequestContext( new[] {$"{resource}/.default" });
            AccessToken fullToken = await credential.GetTokenAsync(tokenRequestContext, cancellationToken).ConfigureAwait(false);
            return fullToken.Token;
        }
    }
}

OUTPUT

© www.soinside.com 2019 - 2024. All rights reserved.