Synchronous retrieving of access token when using Azure.Identity leads to performance issues
See original GitHub issueRequirements We have the requirement to provide a constantly fast Web Api with response times of less than 50ms. The Web Api provides data from Azure Sql.
Current Solution
We use Managed Identity to authorize access from an Azure App Service to Azure Sql.
In order to have an authorized SqlConnection for EF Core we use our own DbConnectionInterceptor
.
public class AADTokenInjectorDbInterceptor : DbConnectionInterceptor
{
private readonly IAzureCredentialProviderFactory _azureCredentialProviderFactory;
private readonly IMeasureTime _measureTime;
private static readonly string[] Scopes = { "https://database.windows.net/.default" };
private AccessToken _accessToken;
public AADTokenInjectorDbInterceptor(IMeasureTime measureTime)
{
_measureTime = measureTime;
}
public override async Task<InterceptionResult> ConnectionOpeningAsync(
DbConnection connection,
ConnectionEventData eventData,
InterceptionResult result,
CancellationToken cancellationToken = default)
{
var sqlConnection = (SqlConnection)connection;
await RefreshTokenIfNecessary();
sqlConnection.AccessToken = _accessToken.Token;
return result;
}
private async Task RefreshTokenIfNecessary()
{
if (_accessToken.ExpiresOn != default && DateTimeOffset.UtcNow < _accessToken.ExpiresOn)
return;
_accessToken = await _measureTime.For("Refresh token for SQL Server",
async () =>
{
var tokenCredential = new ChainedTokenCredential(new AzureCliCredential(), new ManagedIdentityCredential());
return await tokenCredential.GetTokenAsync(new TokenRequestContext(Scopes), CancellationToken.None);
});
}
}
Issue The “synchronous” retrieving of an access token, which can take several seconds, slows down requests constantly. e.g. Sql query (5ms) + retrieving access token (1500ms) = 1505ms instead of 5ms.
Failed Solution Idea
We tried to cache the access token using ASP.NET Core Background Service in order to remove the blocking/synchronous call from our own DbConnectionInterceptor
implementation. This idea back fired as we assumed TokenCredential.GetTokenAsync
would give us a new access token which it doesn’t.
Questions Is there anyway on how we can force Azure.Identity to give us a new access token? Are there any other solutions to achieve a constantly fast responding Web Api that access Sql Server using Managed Identity?
Issue Analytics
- State:
- Created 3 years ago
- Comments:14 (6 by maintainers)
Top GitHub Comments
Hi,
Can this be reopened? We are also seeing occasional slow requests to the database when the managed identity is used. We don’t use any interceptor and I am guessing this is happening because sometimes obtaining the token is slow.
@Rookian Thanks for reaching out to us with this issue, and I’m sorry your having this trouble.
Azure.Identity doesn’t provide an mechanism to force issuing a new token because there is no way for the library to guarantee this as the token can be cached at many levels, including the STS. So any mechanism we would add to enable this would only be a best attempt, and unreliable.
Also I would second what @jongio suggested about reordering your credentials putting the
ManagedIdentityCredential
before theAzureCliCredential
, I think that the long delays you’re seeing in acquiring a token (> 1sec) are probably due to the theAzureCliCredential
. This credential shells out the to the Azure CLI to obtain a token and the CLI startup can easily take as long as the delays your seeing. Could you try switching the ordering of your credentials and see if you’re still seeing the same latency when deployed to a host with managed identity enabled?If this still doesn’t fix the problem, I think your background refresh approach could also be a viable work around, but since you cannot guarantee you’ll get a new token when calling
GetTokenAsync
I would suggest simply doing this refresh more frequently.