SQL 服务器身份验证的独立 Azure 函数托管标识

Isolated Azure Function Managed Identity for SQL Server Auth

我有一个 .NET 5 Azure Function 运行 FUNCTIONS_WORKER_RUNTIME 配置值 dotnet-isolated

函数应用需要使用 EF Core 5.0.6 连接到 Azure SQL 数据库。

我按照 的指导进行 EF 配置。

我的习惯 dbcontext 现在是:

public class SmsOrderContext : DbContext
{
    private readonly AzureServiceTokenProvider azureServiceTokenProvider;

    public SmsOrderContext(DbContextOptions<SmsOrderContext> options, AzureServiceTokenProvider azureServiceTokenProvider) : base(options)
    {
        RelationalDatabaseCreator databaseCreator =
                    (RelationalDatabaseCreator)this.Database.GetService<IDatabaseCreator>();
        databaseCreator.EnsureCreated();
        this.azureServiceTokenProvider = azureServiceTokenProvider;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        SqlConnection connection = new SqlConnection();
        string? envConString = Environment.GetEnvironmentVariable(ConfigConstants.SqlSvrConnString);
        connection.ConnectionString = envConString ?? "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=SmsRouter";
        if (azureServiceTokenProvider != null)
            connection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/").Result;
        optionsBuilder.UseSqlServer(connection);
    }
}

存在检查 SqlSvrConnString 环境变量的条件,这样我就可以在本地 运行 应用程序 - 它使用 localdb(这工作正常)而不是 Azure

在program.main我有:

.ConfigureServices(s =>
{
    s.AddSingleton<AzureServiceTokenProvider>(new AzureServiceTokenProvider());
    s.AddDbContext<SmsOrderContext>();
}

在我的函数应用程序中,Identity\System 的“状态”切换设置为“打开”

当我触发 Azure 函数(从 http 请求)时,我在 Application Insights 中看到以下异常:

Failure Exception: Microsoft.Data.SqlClient.SqlException (0x80131904):
Login failed for user ''

我认为这表明身份没有传递到 Sql 服务器?谁能看看我哪里出错了?

如果您想使用Azure MSI访问AzureSQL,请参考以下步骤

  1. 启用 MSI

  2. 创建 Azure AD 组

Connect-AzureAD
New-AzureADGroup -DisplayName "My new group" -MailEnabled $false -SecurityEnabled $true -MailNickName "NotSet"
  1. 将 MSI 添加为组成员
Add-AzureADGroupMember -ObjectId "the id of the group" -RefObjectId "the id of the msi"
  1. 将组设置为 SQL 服务器 Azure AD 管理员

  2. 代码

我的DbContext

using Microsoft.EntityFrameworkCore;
using Microsoft.Data.SqlClient;
using Microsoft.Azure.Services.AppAuthentication;
namespace httpfun{

   public class BloggingContext : DbContext
        {
           private readonly AzureServiceTokenProvider azureServiceTokenProvider;

    public BloggingContext(DbContextOptions<BloggingContext> options, AzureServiceTokenProvider azureServiceTokenProvider) : base(options)
    {
       
        this.azureServiceTokenProvider = azureServiceTokenProvider;
    }
            public DbSet<Blog> Blogs { get; set; }
             

        protected override void OnConfiguring(DbContextOptionsBuilder options)
          {
            SqlConnection connection= new SqlConnection();
            connection.ConnectionString="Server=tcp:<>database.windows.net,1433;Database=<>;";
            connection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/").Result;
            options.UseSqlServer(connection);
          }
         }

        public class Blog
        {
            public int BlogId { get; set; }
            public string Url { get; set; }

            
        }

}

我的Program.cs

using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Functions.Worker.Configuration;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;

namespace httpfun
{
    public class Program
    {
        public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                .ConfigureServices(services=>{
                    services.AddSingleton<AzureServiceTokenProvider>(new AzureServiceTokenProvider());
                    services.AddDbContext<BloggingContext>();
                    
                })
                .Build();

            host.Run();
        }
    }
}

我的功能代码(我用HTTP触发器测试)

using System.Collections.Generic;
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace httpfun
{
    public  class HttpTrigger1
    {
        private   readonly  BloggingContext _context;

        public HttpTrigger1(BloggingContext context){
               this._context=context;
        }

        [Function("HttpTrigger1")]
        public  HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
            FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("HttpTrigger1");
            logger.LogInformation("C# HTTP trigger function processed a request.");

            
                logger.LogInformation("Inserting a new blog");
                _context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
                _context.SaveChanges();
            

            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

            response.WriteString("Welcome to Azure Functions!");

            return response;
        }
    }
}