Update to Azure.Identity 1.8.0 dependency
Hello,
Maybe you already have this in mind but App Insights relies on Azure.Identity to get bearer token in case you want to use AAD authentication to send metrics to App Insights. The problem is that before version 1.8.0 of Az.Identity the ManagedIdentityCredential was not doing any token cache, neither App Insights do (there is a dicussion for this here: https://github.com/microsoft/ApplicationInsights-dotnet/issues/2539#issuecomment-1341300967), which results in a lot of token generation roundtrip with performance degradation. On Azure functions the version used for Az.Identity is 1.5.0, so could you plan to rollout the Az.Identity file version in the Azure funtions to 1.8.0 or maybe is there a way to update it manually?
Regards.
@a99cl208 We will check this with our next level team and update you.
@a99cl208 what version of Functions are you using? In 4.0, this is not a unified dependency, and you should be able to use any version you wish.
Did you run into problems when trying to reference 1.8.0?
I use 4.0 yes still i'm not able to use the version is want.
Maybe let's add some context. My code reference the latest app insight version (so 2.21.0 for now) while it seems that the installed version on the function apps are the 2.20.0. Normally to enable AAD you just have to add configuration.SetAzureTokenCredential(tokenCredential); on your TelemetryConfiguration class. On an API i use a class that inherits from IConfigureOptions<TelemetryConfiguration> to do so, but this does not work in a function app since the TelemetryConfiguration is created using TelemetryConfiguration.CreateDefault(). So instead I use a ITelemetryModule implementation which is called after the configuration creation (the details of implementation is here: https://github.com/Azure/azure-webjobs-sdk/blob/dev/src/Microsoft.Azure.WebJobs.Logging.ApplicationInsights/Extensions/ApplicationInsightsServiceCollectionExtensions.cs#L281)
But if i do a configuration.SetAzureTokenCredential(tokenCredential); in my module method i get a reflection issue. So instead I had to make some ugly code that gets the applicable library version and generate the appropriates class. Here is the code:
public void Initialize(TelemetryConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(configuration);
// Since the Azure Function host resolves its own version of Azure identity library, we need to use reflection to retrieve
// the correct type to instanciate.
// We retrieve the correct Azure.Core.TokenCredential type from which to inherit
var assembly = configuration.GetType().Assembly;
var reflectionCredentialEnvelope = assembly.GetType("Microsoft.ApplicationInsights.Extensibility.Implementation.Authentication.ReflectionCredentialEnvelope")!;
var tokenCredentialType = (Type)reflectionCredentialEnvelope.GetMethod("GetTokenCredentialType", BindingFlags.NonPublic | BindingFlags.Static)!.Invoke(null, null)!;
// Then we find the corresponding Azure.Identity.DefaultAzureCredential type among loaded assemblies.
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var defaultAzureCredentialAssembly = assemblies
.Where(x => x.FullName != null && x.FullName.StartsWith("Azure.Identity,"))
.FirstOrDefault(x =>
{
var candidate = x.GetType("Azure.Identity.DefaultAzureCredential");
return candidate != null && candidate.IsSubclassOf(tokenCredentialType);
});
if (defaultAzureCredentialAssembly == null)
{
// If no loaded assembly correspond, we try to find the assembly in the same folder that the Azure.Core.TokenCredential type assembly location.
string candidate = Path.Combine(Path.GetDirectoryName(tokenCredentialType.Assembly.Location)!, "Azure.Identity.dll");
if (File.Exists(candidate))
{
defaultAzureCredentialAssembly = Assembly.LoadFile(candidate);
}
else
{
// As a last chance we let the Framework resolve.
defaultAzureCredentialAssembly = Assembly.Load("Azure.Identity");
}
}
var defaultAzureCredentialType = defaultAzureCredentialAssembly.GetType("Azure.Identity.DefaultAzureCredential")!;
var defaultAureCredential = Activator.CreateInstance(defaultAzureCredentialType, new object[] { false });
configuration.SetAzureTokenCredential(defaultAureCredential);
}
Notes that their is also some weird stuff done by app insight to get the token credential using reflection: https://github.com/microsoft/ApplicationInsights-dotnet/blob/23181177558f2b2879dc6bf411fdf0b7d3edc479/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Authentication/ReflectionCredentialEnvelope.cs#L20 I guess its to avoid having a strong reference to Az.Identity.
You can probably reproduce my use case easily with an empty function, a custom itelemetrymodule that does configuration.SetAzureTokenCredential(tokenCredential); and register it in the FunctionStartup class (from Microsoft.Azure.Functions.Extensions NuGet).
So it means i am stick to the version deployed with the infrastructure which is the 1.5.0. What it a bit specific in my case is that the config occurs during the startup, and the caller of my telemetry module is the function host itself. I never had any version conflict issue anywhere else in the code base.
@fabiocav Please find the provided information from the customer.
Any update on this?