问题
I'm trying to retrofit MSI to an existing app.
The original app's DbContext used only a Constructor that found a ConnectionString by the same name in the web.config.
I've modified it to use a DbConnectionFactory to inject an AccessToken.
public class AppCoreDbContext : DbContext {
public AppCoreDbContext() : this("AppCoreDbContext")
{
}
public AppCoreDbContext(string connectionStringOrName) : base( OpenDbConnectionBuilder.Create(connectionStringOrName).Result, true)
{
}
...etc...
}
The class that it is invoking looks like:
public static class OpenDbConnectionBuilder
{
public static async Task<DbConnection> CreateAsync(string connectionStringName)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
var dbConnection = DbProviderFactories
.GetFactory(connectionStringSettings.ProviderName)
.CreateConnection();
dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
await AttachAccessTokenToDbConnection(dbConnection);
// Think DbContext will open it when first used.
//await dbConnection.OpenAsync();
return dbConnection;
}
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;
}
string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
sqlConnection.AccessToken = accessToken;
}
}
Which invokes
// Refer to: https://winterdom.com/2017/10/19/azure-sql-auth-with-msi
public static class AppCoreDbContextMSITokenFactory
{
private const String azureSqlResource = "https://database.windows.net/";
public static async Task<String> GetAzureSqlResourceTokenAsync()
{
var provider = new AzureServiceTokenProvider();
var result = await provider.GetAccessTokenAsync(azureSqlResource);
return result;
}
}
The result of the above is that when tracking it with a debugger, it gets to
var result = await provider.GetAccessTokenAsync(azureSqlResource);
then hangs for ever.
Note: I'm working on a personal machine, not joined to the organisation domain -- but my personal MSA has been invited to the organisation's domain.
Admittedly, I've taken a hiatus from development for a couple of years, and the hang is probably due to having made a mistake around await (always been rough on understanding that implicitly)... but while trying to figure that out, and the documentation is pretty sparse, would appreciate feedback as to whether the above was the intended approach for using MSI.
I'm wondering:
- When deploying to Azure, we can tell the ARM to create the Identity -- when developing, how do we tell the local machine to use MSI?
- If on the dev machine the connection string is to a local db, and I create and add the token anyway, will it ignore it, or raise an exception.
- This is a bit beyond the scope of discussing MSI, but I've never before created a dbConnection to use within a DbContext. Does anyone know the pros/cons of the DbContext 'owning' the connection? I'm assuming that it would be wiser to own & close the connection when the dbcontext is closed.
Basically...this is all new, so would appreciate any advice on getting this working -- the concept of being able to deploy without secrets would be awesome and would really like to get this demo working.
Thanks very much!
回答1:
Hello user9314395: Managed Service Identity only works with resources running on Azure. While we don't support the local development scenario, you might consider looking into using the following (preview) library: https://docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication
来源:https://stackoverflow.com/questions/49531754/app-service-to-entityframework-using-msi