1

I am currently migrating a dotnet-isolated v3 function (.net 5) to a non-isolated v4 azure function (.net 6)

in v3 dotnet-isolated I had a console application and so a Program.cs which contained the following code:

public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureAppConfiguration(AddAzureAppConfig)
                .Build();

            host.Run();
        }

     private static void AddAzureAppConfig(IConfigurationBuilder builder)
        {
            var azureAppConfigurationEndpoint = Environment.GetEnvironmentVariable("AzureAppConfiguration");

            builder.AddAzureAppConfiguration(options =>
                  options.Connect(azureAppConfigurationEndpoint).ConfigureKeyVault(kv =>
                  {
                      kv.SetCredential(new DefaultAzureCredential());
                  }).Select(KeyFilter.Any, LabelFilter.Null)
            );
        }

Now in v4 I have a library instead and so no program.cs. Instead I created a Startup.cs derived from FunctionsStartup

 public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddHttpClient();
...
}
}

As far as I understood from this StackOverFlow-Question v4 Azure Functions don't have any IConfigurationBuilder and don't need to if you directly want to access any configuration values.

Now my issue is that while AddAzureAppConfiguration inside the Microsoft.Extension.Configuration.AzureAppConfigurationExtensions has a overload I could use (AddAzureAppConfiguration(this IServiceCollection services)) but it is missing the Action<AzureAppConfigurationOptions> action parameter (which the IConfigurationBuilder- variant had) which I need to add the KeyVault options.

What do I have to modify to use the same approach I was using with my AddAzureAppConfig() that worked on the v3 isolated console application approach?

Ole Albers
  • 8,715
  • 10
  • 73
  • 166
  • Have you tried not using '.ConfigureKeyVault()' at all and just configure everything in Azure? I know that's not your question but maybe something that might help. Here's also some more information (https://stackoverflow.com/questions/62960764/how-to-modify-iconfiguration-natively-injected-in-azure-functions/63124002#63124002) – lopezbertoni Mar 10 '22 at 17:02

2 Answers2

2

You can override the ConfigureAppConfiguration method in the FunctionsStartup. Inside the method, you can call ConfigurationBuilder.AddAzureKeyVault which is very similar to function v3.

Example below:

    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {


        }

        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            var builtConfig = builder.ConfigurationBuilder.Build();
            var keyVaultEndpoint = builtConfig["AzureKeyVaultEndpoint"];

            if (!string.IsNullOrEmpty(keyVaultEndpoint))
            {

                var config = builder.ConfigurationBuilder
                        .AddAzureKeyVault(keyVaultEndpoint)
                    .Build();

                var kvSecret = config["kvSecretName"];

            }
        }
    }

The AzureKeyVaultEndpoint is passed in the local.settings.json for local env and in the AppConfig for the Azure env.

Anthony C
  • 2,117
  • 2
  • 15
  • 26
1

A better title: How do I configure key vault for Azure App Configuration within a .NET Isolated Azure Function?

For those that are looking for a .NET 6 program.cs example, here is what your program.cs code should look like:

using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;


var host = new HostBuilder()
    .ConfigureAppConfiguration(builder =>
    {
        // You might need this depending on your local dev environment
        // var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });
        var credential = new DefaultAzureCredential();

        // Required NuGet packages for Azure App Configuration:
        // 1. Azure.Identity
        // 2. Microsoft.Extensions.Configuration.AzureAppConfiguration

        var azureAppConfigurationEndpoint = Environment.GetEnvironmentVariable("AzureAppConfigurationEndpoint");

        if (string.IsNullOrWhiteSpace(azureAppConfigurationEndpoint) == false)
        {
            builder.AddAzureAppConfiguration(options =>
            {
                options.Connect(new Uri(azureAppConfigurationEndpoint), credential)
                    .ConfigureKeyVault(kv =>
                    {
                        kv.SetCredential(credential);
                    });
            });
        }
    })
    .ConfigureFunctionsWorkerDefaults(builder =>
    {

    })
    .ConfigureServices((builder, sc) =>
    {
    
    })
    .Build();

host.Run();

Assumptions

  • Your Azure App Configuration endpoint URL is in local.settings.json in a key called "AzureAppConfigurationEndpoint"

Warnings

  • If your intent is to override a connection string for bindings like ServiceBusTrigger or EventHubTrigger for local development/debugging, it will NOT work with ISOLATED Azure Functions! You have two options with ISOLATED Azure Functions:
    1. Put the connection string in the local.settings.json file when developing locally. In the cloud, use the key vault reference syntax to get in key vault entries in your bindings.
    2. Create a connection string that doesn't have any sensitive permission data in it. Give developers permissions in the dev environment (either directly or via a group) to access the resource . In the cloud, use managed identities and grant the Azure Function permission to use the resource.

References

David Yates
  • 1,935
  • 2
  • 22
  • 38
  • Thanks David. But sometimes, we want to override not because of trust, but because we deploy the same build through an SDLC, need to pick up different values in each environment, or initialize complex objects for multiple projects in a solution. From the "it will not work with ISOLATED" comment above, it appears that Functions as this point are a dead end. I've wasted 4 days this week trying to add a simple module to an existing function, which forced an upgrade. Docs are abysmal, key functionality is black-boxed, and I'm ready to delete it and move the logic back to a webjob. – Brett May 26 '23 at 04:55