Configure Applications with App Configuration and Key Vault

The Azure Key Vault provides a great service to store application secrets and use them to configure your applications; however, with relatively low limits some applications referencing Key Vault with a lot of secrets or even clustered applications referencing fewer secrets can get rate limited and experience slow startup performance. You should instead use Azure App Configuration to store non-secrets and define references to secrets in Key Vault to reduce the number of calls made to Key Vault.

Examples of non-secrets that should be stored in App Configuration:

  • Client application IDs
  • IP addresses
  • Service endpoints
  • Service configuration parameters
  • Usernames

Examples of secrets that should be stored in Key Vault:

  • Client application secrets
  • Connection strings
  • Passwords
  • Shared access keys
  • SSH keys

Getting started

To build and run this sample you will need:

Software:

Azure services:

  • App Configuration

  • Key Vault

  • (Optional) App Service - needed to deploy the web application to Azure, which is provisioned in the Bicep template.

    Note

    App Service has support for referencing Key Vault secrets directly, but is used only as an example how to configure a web site to use App Configuration. If you choose to deploy your web application to another service, the same principles to configure the App Configuration connection string still apply.

  • (Optional) Application Insights - to monitor web traffic and application traces, which is not provisioned in the Bicep template.

Deploy to Azure

To deploy the template manually, make sure your Azure CLI is up to date and run:

az bicep install # if deploying azuredeploy.bicep
az group create --location {location} --resource-group {group-name}
az deployment group create --resource-group {group-name} --template-file azuredeploy.bicep # or azuredeploy.json

There are a number of parameters you can optional set. View the template for details.

After deployment completes, make note of the output variables as shown in the example below:

{
  "outputs": {
    "appConfigConnectionString": {
      "type": "String",
      "value": "Endpoint=https://{appconfig-host-name}.azconfig.io;Id={id};Secret={secret}"
    },
    "siteUrl": {
      "type": "String",
      "value": "https://{site-host-name}.azurewebsites.net/"
    },
    "vaultUrl": {
      "type": "String",
      "value": "https://{vault-host-name}.vault.azure.net/"
    }
  }
}

Building the sample

You can build, run, and even deploy the sample using Visual Studio, Visual Studio Code, or the .NET command line interface (CLI). Using the dotnet CLI, for example, within the directory containing the sample application source run:

dotnet build

Running the sample

Before you can run the sample locally you'll need to grant access to the Key Vault for your local user account or service principal. If you're logged into your tenant in Visual Studio and the Azure CLI using the same principal, you can find the UPN or SPN the same way:

az account show

If you're logged in as a user, you will see your email address and can pass that to the --upn parameter:

az keyvault set-policy -n {vault-host-name} --upn {user@domain.com} --secret-permissions get

If you're logged in as a service principal, the user.type will be servicePrincipal and you'll pass the the user.name to the --spn parameter:

az keyvault set-policy -n {vault-host-name} --spn {spn} --secret-permissions get

Next you'll need to add the App Configuration connection string from the template deployment outputs to your local user secrets:

  1. Right-click on the project

  2. Click Managed User Secrets

  3. Add a variable named ConnectionStrings:AppConfig with the value of the appConfigurationConnectionString output variable:

    {
      "ConnectionStrings:AppConfig": "Endpoint=https://{appconfig-host-name}.azconfig.io;Id={id};Secret={secret}"
    }
    
  4. Click Debug -> Start debugging (F5) to run.

Deploying the sample

See the ASP.NET quickstart for instructions to deploy for Visual Studio, Visual Studio Code, and the dotnet CLI. For Visual Studio and Visual Studio Code, make sure you select your existing resource if you deployed the Bicep template above; otherwise, for the dotnet CLI you can deploy to an existing resource by configuring Git support and pushing source, which will be built automatically on the host.

Configuring App Configuration with Key Vault references

Using Azure App Configuration is an efficient way to store application configuration key-value pairs, and can reference Key Vault secrets. The App Configuration service itself doesn't need access to these secrets, but your application - like the sample web application here - will need nothing more than get access to Key Vault secrets. Configuration in ASP.NET enumerates key-value pairs from a number of configured providers, which not only requires both list and get permissions to Key Vault but is the main cause of application startup performance problems or even failures. By using the Microsoft.Extensions.Configuration.AzureAppConfiguration package you can reduce the calls to Key Vault while the package itself will automatically fetch secrets' values as needed.

  1. Add the following package to your project:

    dotnet add package Azure.Identity
    dotnet add package Microsoft.Extensions.Configuration.AzureAppConfiguration
    
  2. At the top of Program.cs (or wherever your entry point is defined) add the following using statements:

    using Azure.Identity;
    using Microsoft.Extensions.Configuration;
    
  3. Update the CreateHostBuilder method to call the ConfigureAppConfiguration extension method as shown below:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureAppConfiguration(config =>
                {
                    var settings = config.Build();
                    var connectionString = settings.GetConnectionString("AppConfig");
    
                    config.AddAzureAppConfiguration(options =>
                    {
                        options.Connect(connectionString);
                        options.ConfigureKeyVault(options =>
                        {
                            options.SetCredential(new DefaultAzureCredential());
                        });
                    });
                })
                .UseStartup<Startup>();
            });
    

This uses the ConnectionStrings:AppConfig defined within the deployed web application or locally in your user secrets to connect to Azure App Configuration. Whenever a referenced secret is enumerated, the configuration provider will automatically retrieve it using the DefaultAzureCredential that is designed to work optimally in both development and production environments without code changes. When running from the deployed web application, the web application's system identity is used to connect to Key Vault. When running locally, a number of your local credentials are attempted including your Visual Studio, Visual Studio Code, and Azure CLI credentials. If you see an error message that your local application is not authorized for the deployed Key Vault, see our troubleshooting section for help.

Caching clients

You can also reduce the number of calls to Azure Key Vault by caching your SecretClient or any other Key Vault SDK client. Our clients are designed to reuse an HttpClient by default and cache authentication bearer tokens for service like Key Vault to reduce the number of calls to authenticate. You can use our Microsoft.Extensions.Azure to cache clients and use them elsewhere:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAzureClients(config =>
    {
        config.UseCredential(new DefaultAzureCredential());

        // Assumes the deployed Key Vault URL is stored in a variable named KEYVAULT_URL.
        config.AddSecretClient(new Uri(Configuration["KEYVAULT_URL"]));
    });

    services.AddRazorPages();
}

In ASP.NET Razor pages as an example, you can then inject them into the page:

@using Azure.Security.KeyVault.Secrets;
@inject SecretClient SecretClient

<p>Connected to @SecretClient.VaultUri</p>

Additional documentation