Может ли MSI работать с EF CodeFirst?
Я застрял на этом довольно долго, и мне не повезло, что я продвинулся сам.
Я пытаюсь подключиться из службы приложений Azure к управляемой базе данных EF CodeFirst с помощью токена MSI.
При развертывании службы приложений с использованием ARM я создал вывод, который обеспечил создание субъекта службы:
{
"principalId":"98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx","
tenantId":"e6d2d4cc-b762-486e-8894-4f5f440dxxxx",
"type":"SystemAssigned"
}
В Куду переменные среды показывают, что он устанавливается:
MSI_ENDPOINT = http://127.0.0.1:41239/MSI/token/
MSI_SECRET = 7C1B16Fxxxxxxxxxxxxx
Я предоставил на портале Azure строку подключения следующим образом:
Data Source=nzmoebase0000bt.database.windows.net;Initial Catalog=nzmoebase0001bt;Connect Timeout=300;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=300;
Я добавил принципала в базу данных в качестве владельца.
Note: I cannot do the same for the master db.
Токен добавляется в DbContext следующим образом:
Токен добавляется с помощью:
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;
}
При трассировке токен:
.eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI....
Который декодировал с использованием jwt.io дал:
{
"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]
Я добавил Persist Security Info = True
согласно нескольким рекомендациям в сети, но это не сделало ничего обнаружимого.
Data Source=nzmoebase0000bt.database.windows.net;Initial Catalog=nzmoebase0001bt;MultipleActiveResultSets=False;Persist Security Info = True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
Я получаю ошибку:
[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.]
Кто-нибудь получил соединение с базой данных, используя CodeFirst, с миграциями и MSI? В этот момент, после нескольких недель, когда я действительно застрял, я начинаю задумываться, возможно ли это.
Спасибо за любую помощь - даже если только доказательство того, что она может работать, для начала.
0 ответов
К сожалению, насколько мне известно, нет. Основной камень преткновения для проекта, который должен был использовать небезопасные строки подключения, загруженные с помощью имени / пароля.
Вы можете установить токен доступа для соединения SQL следующим образом:
- Установите
Microsoft.Azure.Services.AppAuthentication
пакет Nuget настройте свой контекстный класс следующим образом:
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; } }