Недавно я настроил нашу службу приложений Azure и Azure SQL Server для использования управляемого доступа к удостоверениям. Службе приложений назначено управляемое удостоверение, назначенное системой, и назначена правильная роль владельца базы данных SQL. Когда я публикую свой код в службе приложений, он отлично работает и может получить доступ к базе данных.
Моя проблема в том, что я не могу подключиться к базе данных через свое приложение при локальном запуске через Visual Studio. Моя учетная запись Azure настроена как администратор Azure Active Directory на SQL Server, и я могу открывать подключение и выполнять запросы через Azure Data Studio после входа в систему.
Я использую ту же учетную запись через Visual Studio, даже отсоединил и снова связал ее в меню «Инструменты» -> «Параметры» -> «Аутентификация службы Azure/выбор учетной записи». Но когда я пытаюсь запустить приложение локально, я получаю сообщение об ошибке ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.
Ошибка не дает мне много работы, потому что я не уверен, как увидеть полное представление о том, что пытается пройти аутентификацию. Я не использую какой-либо код на своей стороне для получения токена доступа, поскольку я просто позволяю Microsoft SQLClient получить его для меня через строку подключения.
Вот полная трассировка стека ошибки, все, что может указать мне правильное направление, будет оценено. Я предполагаю, что это как-то связано с тем, что Visual Studios, вероятно, нужно разрешить получить токен доступа от моего имени, но я подумал, что, поскольку я вошел в свою учетную запись Azure, это может не иметь значения.
at Microsoft.Data.ProviderBase.DbConnectionPool.CheckPoolBlockingPeriod(Exception e)
at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.Enumerator.MoveNext()
at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
Azure.RequestFailedException: A socket operation was attempted to an unreachable network. (169.254.169.254:80)
---> System.Net.Http.HttpRequestException: A socket operation was attempted to an unreachable network. (169.254.169.254:80)
---> System.Net.Sockets.SocketException (10051): A socket operation was attempted to an unreachable network.
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(HttpMessage message, Boolean async)
--- End of inner exception stack trace ---
at Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(HttpMessage message, Boolean async)
at Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline)
at Azure.Core.Pipeline.RequestActivityPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Core.Pipeline.RetryPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async)
at Azure.Identity.ImdsManagedIdentitySource.<AuthenticateAsync>d__15.MoveNext()
at Azure.Identity.ManagedIdentityClient.<AuthenticateCoreAsync>d__17.MoveNext()
at Azure.Identity.ManagedIdentityClient.<AppTokenProviderImpl>d__18.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<SendTokenRequestToProviderAsync>d__4.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<FetchNewAccessTokenAsync>d__3.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<ExecuteAsync>d__2.MoveNext()
at Microsoft.Identity.Client.Internal.Requests.RequestBase.<RunAsync>d__12.MoveNext()
at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.<ExecuteAsync>d__3.MoveNext()
at Azure.Identity.AbstractAcquireTokenParameterBuilderExtensions.<ExecuteAsync>d__0`1.MoveNext()
at Azure.Identity.MsalConfidentialClient.<AcquireTokenForClientCoreAsync>d__21.MoveNext()
at Azure.Identity.MsalConfidentialClient.<AcquireTokenForClientAsync>d__20.MoveNext()
at Azure.Identity.ManagedIdentityClient.<AuthenticateAsync>d__16.MoveNext()
at Azure.Identity.ManagedIdentityCredential.<GetTokenImplAsync>d__16.MoveNext()
at
Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage)
at Azure.Identity.ManagedIdentityCredential.<GetTokenImplAsync>d__16.MoveNext()
at Azure.Identity.ManagedIdentityCredential.<GetTokenAsync>d__14.MoveNext()
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.<AcquireTokenAsync>d__17.MoveNext()
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.<>c__DisplayClass147_1.<<GetFedAuthToken>b__1>d.MoveNext()
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
Соответствующая информация о соединении DbContext. В настоящее время используется версия 7.0.3 Microsoft.EntityFrameworkCore для класса DbContext.
public class DbEntities: DbContext
{
public DbEntities() : base() { }
//All DbSet<...> classes here
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"));
}
}
Соответствующий JSON-файл AppSettings
{
"ConnectionStrings": {
"DB_CONNECTION_STRING": "Server=tcp:MY-SERVER.database.windows.net;Initial Catalog=development;Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Authentication=\"Active Directory Managed Identity\";"
},
}
@MdFaridUddinKiron Полагаю, я хочу, чтобы поведение было таким же, как если бы приложение было развернуто. Так что прямо сейчас мне просто нужно подключиться к базе данных через локальное приложение. Это существующее приложение, которое я обновляю для работы с управляемой идентификацией. В настоящее время используется DbContext
, предоставляемый в версии 7.0.3 пакета Microsoft.EntityFrameworkCore. Я добавил соответствующую информацию о подключении в свой исходный пост.
Попробуйте войти в нужную учетную запись с помощью Azure CLI (az login
). Хотя я не уверен, что это сработает именно для этой строки подключения. Вам может понадобиться Active Directory Default
для аутентификации.
@MdFaridUddinKiron По сути, я пытаюсь ответить на вопрос, почему я могу открыть соединение с базой данных через Azure Data Studio, но не через свое локальное приложение в Visual Studios, когда моя учетная запись Microsoft подключена к обоим.
Вход @AlexAIT с помощью azure cli не имел значения. Все еще получаю те же ошибки. Попробую Active Directory Default
и посмотрим, изменит ли это что-нибудь
@AlexAIT Хорошо, изменение строки подключения для использования Active Directory Default
вместо Active Directory Managed Identity
, похоже, позволяет ему работать как в localhost
, так и в моей службе приложений Azure. Не знаю, почему... но я возьму это.
Круто, я разместил это как ответ, включая некоторую дополнительную информацию.
Используя Authentication=\"Active Directory Managed Identity\"
, вы укажете своему приложению использовать только управляемую аутентификацию. Это можно использовать только в том случае, если вы действительно работаете в качестве ресурса Azure. Вы не можете использовать аутентификацию Managed Identity с вашей личной учетной записью.
Используя Active Directory Default
в качестве значения, система попробует несколько вариантов:
Выполняйте аутентификацию с помощью удостоверения Azure AD, используя неинтерактивные механизмы без пароля, включая управляемые удостоверения, Visual Studio Code, Visual Studio, Azure CLI и т. д.
Итак, чего вы хотите достичь? Хотите подключить azure sql к своему приложению локально или хотите аутентифицировать свое приложение? Кроме того, ему также необходимо знать, что вы пытаетесь реализовать, и вашу конфигурацию помимо трассировки стека.