Azure-Functions icon indicating copy to clipboard operation
Azure-Functions copied to clipboard

Update to Azure.Identity 1.8.0 dependency

Open a99cl208 opened this issue 3 years ago • 5 comments

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 avatar Dec 08 '22 09:12 a99cl208

@a99cl208 We will check this with our next level team and update you.

ramya894 avatar Dec 12 '22 07:12 ramya894

@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?

fabiocav avatar Dec 13 '22 16:12 fabiocav

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.

a99cl208 avatar Dec 13 '22 17:12 a99cl208

@fabiocav Please find the provided information from the customer.

ramya894 avatar Dec 14 '22 12:12 ramya894

Any update on this?

GABRIELNGBTUC avatar Apr 04 '24 12:04 GABRIELNGBTUC