Can MSI work with EF CodeFirst?

安稳与你 提交于 2021-02-07 19:39:46

问题


I've gotten stuck on this for quite a while now, with no luck advancing it on my own.

I am trying to connect from an Azure App Service to a EF CodeFirst managed database, using an MSI token.

When I deployed the App Service using ARM I produced an Output that ensured that it created a Service Principal:

 {
  "principalId":"98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx","
  tenantId":"e6d2d4cc-b762-486e-8894-4f5f440dxxxx",
  "type":"SystemAssigned"
 }

In Kudu the environment variables show that it is being installed:

MSI_ENDPOINT = http://127.0.0.1:41239/MSI/token/
MSI_SECRET = 7C1B16Fxxxxxxxxxxxxx

I have provided in the Azure Portal a connection string as follows:

Data Source=nzmoebase0000bt.database.windows.net;Initial Catalog=nzmoebase0001bt;Connect Timeout=300;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=300;

I've added the principal to the database as an Owner.

Note: I cannot do the same for the master db.

The token is added to the DbContext as follows:

The token is being added using:

    static async Task AttachAccessTokenToDbConnection(IDbConnection dbConnection)
    {
        SqlConnection sqlConnection = dbConnection as SqlConnection;
        if (sqlConnection == null)
        {
            return;
        }
        string msiEndpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
        if (string.IsNullOrEmpty(msiEndpoint))
        {
            return;
        }

        var msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET");
        if (string.IsNullOrEmpty(msiSecret))
        {
            return;
        }

        // To get around:
        // "Cannot set the AccessToken property if 'UserID', 'UID', 'Password', or 'PWD' has been specified in connection string."
        var terms = new[] {"UserID","Password","PWD=","UID=" };
        string connectionString = dbConnection.ConnectionString;

        foreach (var term in terms)
        {
            if (connectionString.Contains(term, StringComparison.InvariantCultureIgnoreCase))
            {
                return;
            }
        }

        string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
        sqlConnection.AccessToken = accessToken;
    }

With tracing on, the token is:

 .eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI....

Which decoded using jwt.io gave:

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "FSimuFrFNoC0sJXGmv13nNZceDc",
  "kid": "FSimuFrFNoC0sJXGmv13nNZceDc"
}.{
  "aud": "https://database.windows.net/",
  "iss": "https://sts.windows.net/e6d2d4cc-b762-486e-8894-4f5f440dxxxx/",
  "iat": 1522783025,
  "nbf": 1522783025,
  "exp": 1522786925,
  "aio": "Y2NgYPjNdyJd9zrzpLavJSEzNIuPAAA=",
  "appid": "d1057cea-461b-4946-89a9-d76439c2xxxx",
  "appidacr": "2",
  "e_exp": 262800,
  "idp": "https://sts.windows.net/e6d2d4cc-b762-486e-8894-4f5f440dxxxx/",
  "oid": "98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx",
  "sub": "98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx",
  "tid": "e6d2d4cc-b762-486e-8894-4f5f440dxxxx",
  "uti": "59bqKWiSL0Gf0bTCI0AAAA",
  "ver": "1.0"
}.[Signature]

I Added Persist Security Info = True as per several recommendations on the net, but that did nothing detectable.

Data Source=nzmoebase0000bt.database.windows.net;Initial Catalog=nzmoebase0001bt;MultipleActiveResultSets=False;Persist Security Info = True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

The error I am getting is:

[InvalidOperationException: This operation requires a connection to the 'master' database. Unable to create a connection to the 'master' database because the original database connection has been opened and credentials have been removed from the connection string. Supply an unopened connection.]

Has anyone gotten a connection to a database, using CodeFirst, with Migrations, and MSI? At this point, after several weeks of being really stuck, I'm starting to wonder if it is possible.

Thanks for any help -- even if just proof that it can work, for starters.


回答1:


Unfortunately, to my knowledge, no. A major stumbling block to a project that had to fall back to unsecure Username/password loaded connection strings.




回答2:


You can set the access token on the sql connection like that:

  1. Install the Microsoft.Azure.Services.AppAuthentication nuget package
  2. set up your context class like that:

    public class MyDatabaseContext : DbContext
    {
        public MyDatabaseContext(DbContextOptions<MyDatabaseContext> options)
            : base(options)
        {
            // Get the db connection
            var connection = (SqlConnection)Database.GetDbConnection();
    
            // Add the access token
            connection.AccessToken = new AzureServiceTokenProvider()
                .GetAccessTokenAsync("https://database.windows.net/")
                .ConfigureAwait(false).GetAwaiter().GetResult();
        }
    
        public DbSet<MyTable> MyTable { get; set; }
    }
    


来源:https://stackoverflow.com/questions/50054491/can-msi-work-with-ef-codefirst

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!