ASP.NET Core – How To Use Azure App Configuration and Key Vault for Development and Production

The purpose of this article is to discuss how to use Azure App Configuration and Key Vault both for Development and Production.

In this article will will create an ASP.NET Core MVC web application using Azure AD Single Tenant Authentication and Authorization. We will discuss how the Azure AD configuration, including the Client Secret will be stored in Azure App configuration and Key Vault, and then be made available to read for other developers that we are collaborating with and the Production environment.

The following steps will be involved:

      • Create a development container
      • Create a new ASP.NET Core MVC Web application in the development container
      • Create an Application Registration in Azure Ad and Temporarily configure the application using local appsettings.json file
      • Login to the Azure CLI in the development container
      • Create the following Azure resources:
        • — A Resource Group
          — An App Configuration
          — A Key Vault
          — An App Service Plan
          — An App Service Web App
      • Copy the information from appsettings.json to Azure App Configuration
      • Connect your development environment to Azure
      • Configure the MVC Web Application to read from App Configuration and Key Vault
      • Deploy the Azure App, and discuss why the application doesn’t work right away
      • Configure the Web Application Identity and Key Vault to make the application work
      • Configure the key vault to allow collaborators to download configuration and key vault secrets

Create a Development Container

Create a new folder on your computer somewhere. I will use the name of “azure-app-config-key-vault-demo”. Open the empty folder in Visual Studio Code.

Use the command pallet and select the option to add remote container files to the project.

I will be selecting the options for C#, 6.0, lts of nodejs, and checking the boxes for Azure CLI, and GitHub CLI when going through the rest of the prompts of building this development container.
When prompted click on the “Reopen in Container”. If you missed it, then open the command pallet again and select “Remote Containers: Reopen in Container”

Wait a few moments for the container to start up (as it will say Starting Dev Container…). You can click to show the log if you wish as it builds the container.

Create a new ASP.NET Core MVC Web application in the development container

Once the dev container is created do Ctrl+Shift+` to open a command prompt. In the command prompt enter in the following command

dotnet new mvc --auth SingleOrg --calls-graph
Open the properties/launchSettings.json file as well as the appsettings.json files since we will be reading and writing using information from those files.

Create an Application Registration in Azure AD and temporarily configure the appsettings.json locally

In this example we will be creating an application registration using the azure portal @

Be sure that you are in a directory that you can manage, and then go to the “Azure Active Directory” resource.

    1 – Copy and paste the Domain and TenantId on the Overview page to the appropriate settings in the appsettings.json file.

    2 – Select the “App Registrations” blade.

    3 – Click on the “New registration”

    4 – Give the application registration something meaningful. For this example, I am going to use “SW-AppConfigKeyVaultSample-001”

    5 – I will also be selecting the “Accounts in this organizational directory only”

    6 – Click on the “Register” button

      You will be taken to the App Registration Overview page.

    7 – Copy and paste the application (client) id in to the appropriate settings in the appsettings.json file

    8 – Click on the “Authentication” blade

    9 – Click on the “Add Platform” button

    10 – Select the “Web” button

For the “Redirect URI’s” review your launchSettings.json file that you opened earlier. There will be an applicationUrl key that will have a value similar to: “https://localhost:7266;http://localhost:5115”. For now we are only going to worry about the https URL, and we are going to append the CallbackPath in appsettings.json. So, in this example the Redirect URL would be https://localhost:7266/signin-oidc (your exact settings might be a little different). Be sure to use ID Tokens and Save the changes.
    11 – Click on the “Certificates & secrets” blade.

    12 – Click the + for “New client secret”. Give a description for this secret. I am going to use “Debug” and just use the default expires in 6 months setting. And then click on Add.

    13 – Take note of the “Value” (not the Secret ID). If you navigate away from this page, you will not be able to see the secret again, and you will need to delete and recreate it. Copy and paste that “Value” to the “ClientSecret” key in the appsettings.json file.

As you can tell by this point in the article. It is that ClientSecret that is the real crux of the matter. We do not want our appsettings.json to be saved to our source code repository with the true value.

We are first going to confirm that our application is working locally, and then we will continue on such that our application can read it’s configuration from Azure App Config instead of appsettings.json.

If you go to Program.cs, Visual Studio Code should ask you if you want to add the necessary files to debug the program. Say yes, and after that is complete. If you miss it then you can use the command pallet to “Reload Window”, and after the window has reloaded you will be prompted again.

In the command prompt execute the following command:

dotnet dev-certs https --trust
Hit F5 and confirm that you can sign-in to your account with this MVC app.

Create Azure Resources

All of these items will be created using the Azure Portal @

Create a Resource Group

Search for Resource Group. Give it any name and select a region close to you. I will be using “rg-sw-app-config-key-vault-demo-001”

Create an App Configuration

Select the resource group that you created earlier. Click the Create button to add services to the resource group. Search for “App Configuration” and then click on “Create”

Make sure it is associated with the appropriate Subscription and Resource Group. Select the appropriate Location. Give it a name and select the free pricing tier. I will use the name “app-config-sw-demo-001”

Create a Key Vault

Select the resource group that you created earlier. Click the Create button to add service to the resource group. Search for “Key Vault” and then click on “Create”

Make sure it is associated with the appropriate Subscription and Resource Group. Select the appropriate Location and standard pricing tier. I will use the name: “kv-sw-demo-001”

Create an App Service Plan

Select the resource group that you created earlier. Click the Create button to add service to the resource group. Search for “App Service Plan” and then click on “Create”

Make sure it is associated with the appropriate Subscription and Resource Group. Select the appropriate region and give it a name. I would also recommend changing the SKU and Size to free if possible. I will also be using the Linux version. The name that I will use is: “asp-sw-app-config-key-vault-demo-001”

Create an App Service Web App

Select the resource group that you created earlier. Click the Create button to add service to the resource group. Search for “Web App” and then click on “Create”

Make sure that it is associated with the appropriate Subscription and Resource Group. Give it a name. Select Runtime stack of .NET 6, and Linux OS. Select the appropriate region, and the App Service Plan that you created earlier. I will use the name: “sw-app-config-key-vault-demo-001”

Copy the information from appsettings.json to Azure App Configuration

Using the azure portal go to the App Configuration that you created earlier.

Go to the “Configuration Explorer” blade

Click the drop down on create. Notice that there are two options there: “Key Value”, and “Key Vault Reference”. Most of the things that we will be creating will be Key Values, with the exception of the ClientSecret, which will be a Key Vault Reference.

So pull up your appsettings.json file in your Visual Studio code, and start Copying and Pasting information from appsettings.json to Create, Key Value’s. We are also going to give these Key Values the label of “Development”.

For example, the first thing that we want to configure is the “Instance” key within the “AzureAd” key. When we have nested keys like this, we must delaminate them with a colon. So in this case our Key is going to be “AzureAd:Instance”, and the value is going to be

Specifically, the steps for this are:

      • Click on Create and select Key Value
      • The Key will be: “AzureAd:Instance” (without the quotes)
      • The Value will be: “” (without the quotes)
      • The Label will be: “Development” (without the quotes).
      • You can specify the Content Type as string if you like, but there is honestly nothing wrong if you do not specify that

Repeat those steps for the following keys, and not the AzureAd:ClientSecret

      • AzureAd:Domain
      • AzureAd:TenantId
      • AzureAd:ClientId
      • AzureAd:CallbackPath
You can delete the Certificates section of AzureAd from appsettings.json, and when it comes to the ClientSecret here is what you will do:

    1 – Go to the Key Vault resource that you created in Azure Earlier.

    2 – Go to the “Secrets” blade

    3 – Click on Generate / Import

    4 – The Upload options will be manual

    5 – You can give any name that you like. I will be using: “AzureAdDevelopmentClientSecret”

    6 – The value will be the ClientSecret from your appsettings.json file

    7 – Once that is saved and confirmed to be in your key vault. Return to the App Configuration Azure resource that you created earlier.

    8 – Return to the Configuration Explorer

    9 – Click Create, and this time select Key Vault Reference instead of Key Value.

    10 – The key will need to be “AzureAd: ClientSecret” (without the quotes).

    11 – The label will be “Development” (without the quotes)

    12 – Be sure to select the appropriate Subscription and Resource Group, and Key Vault. Then select the Secret that you created earlier.

For me it looks something like this

When you are done your Configuration Explorer should look something like this:
We could repeat the process for the information in the “DownstreamApi”, and “Logging” sections. But we will forgo that for this demonstration. Although you may choose to do so. What is great about this setup is that the settings from appsettings.json will be merged with the values from Azure App Config, so it is still valid to have information in both, but Azure App Configuration will win when there is a conflict.

Connect your development environment to Azure

At this point the configuration that you want is now in the cloud. So how are you going to get it to your local machine when you are debugging? There are a few options to doing that. For our demonstration we will be putting the Azure App Configuration Connection string as an environment variable, logging in to the Azure CLI, so that when our application code says to use our default credentials it will be authenticating as us.

This demonstration is using a development container, and we want this connection string to the Azure App Configuration to persist as often as possible, but also not be stored in our source code. The approach that we will be taking here is creating an environment file for our docker container, telling git to ignore that environment file, and providing a sample environment file for a future developer to use on their own. We will also update the README to let the developer know that this will be required after cloning the repo.

In the .devcontainer folder create two new files:

      • devcontainer.env
      • devcontainer.env.example

Copy and paste the contents of each file to be the following

APPCONFIG_CONNECTION_STRING=Connection string from <appconfigurl>
In the devcontainer.env.example file replace with the URL in your browser after going to the Azure Portal, browsing to the App Configuration that you created earlier, and clicking on the “Access Keys” blade.

In the devcontainer.env file replace “Connection string form ” with the Connection String Value on the page.

Now modify the devcontainer.json file. Add a “runArgs” key with the following value: [“–env-file”, “.devcontainer/devcontainer.env”]
Now that we have properly configured the ENV file and have told Visual Studio code to load that environment file every time we launch this dev container it is now time to rebuild the dev container.

To rebuild the dev container, open the command pallet in Visual Studio Code (CTRL+SHFIT+P) search for Rebuild and select the option to rebuild the development container.

To confirm that your environment variables loaded do a CTRL+SHIFT+` to open a terminal on the container in Visual Studio Code. Execute the following commands.
You should see the values printed in your console. Here is an example of what mine looks like
So, your development environment knows which app configuration to connect to. But how does Azure Know who is trying to download the configuration, and if you are authorized to download the configuration?

To let your environment know who you are on Azure execute the following command

az login
You will get a browser window. Sign-in on the browser window and return to the console when directed.

The console will say something about who you have signed in as.

If it looks like the console did not sign you in to the tenant or subscription that you want to be signed in to then you can use az login –tenant TENANT_ID to explicitly log in to the tenant that you know has the subscription associated with the app configuration and key vault resources that you created earlier.

To confirm that your environment can now download app configurations execute the following command replacing app-config-sw-demo-001 with your actual Azure App Configuration resource name.

az appconfig kv list --name app-config-sw-demo-001
You should get a JSON response showing you the configurations from Azure App Configuration.

Configure the MVC Web Application to read from App Configuration and Key Vault

Now that we are confident that our development environment can download application configuration let’s work on getting our application to download this information during runtime.

The first thing to do will be to delete the AzureAd key from appsettings.json

The next thing to do would be to download the appropriate nuget packages to work with Azure Key Vault. Go to a terminal and be sure that you are in the correct folder that has the .csproj file for your project.

Execute the following commands:

dotnet add package Azure.Identity
dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore
At this point I would recommend restarting omni sharp since it will be unaware that you just added some packages. To Restart Omni Sharp access the command pallet (Ctrl+Shift+P) search for OmniSharp and select the restart option.
Open Program.cs

After this line of code…

var builder = WebApplication.CreateBuilder(args);
And before this line of code..
// Add services to the container.
var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
Add the following code:
string? appConfigConnectionString = Environment.GetEnvironmentVariable("APPCONFIG_CONNECTION_STRING");
string? aspNetCoreEnvironmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

builder.Host.ConfigureAppConfiguration(configurationBuilder =>
                    if(appConfigConnectionString is not null && aspNetCoreEnvironmentName is not null) {
                        //Connect to your App Config Store using the connection string
                        configurationBuilder.AddAzureAppConfiguration(azureAppConfigurationOptions =>
                            .Select(KeyFilter.Any, LabelFilter.Null)
                            .Select(KeyFilter.Any, aspNetCoreEnvironmentName)
                            .ConfigureKeyVault(kv =>
                                kv.SetCredential(new DefaultAzureCredential());

Some of the code might have red underscores under it. That is fine. Go to them and do a CTRL+ and select the option to include the appropriate “using.” The extra “usings” that get added should be:

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

So, let’s recap what we have done here.

First, we are getting the environment variables that we set in our dockers env file, and we will set as environment variables when we publish our application.

The next part is we are adding an AppConfiguration to the host builder that includes the Azure App Configuration. We tell the app configuration to connect using the connection string that we configured earlier, and to only download configuration that are relevant to our ASPNETCORE_ENVIRONMENT variable (Label). We also told it that we have a key vault configured with our App Configuration. So, any time it finds a Key Vault reference, then use the DefaultAzureCredentials to connect to the key vault and download that secret. And since you did az login earlier. That means your credentials. Any developer that you share this project with will need the same access to the app configuration and key vault. Similarly, any service account that runs your application will need those same permissions. We will go more into that later.

Deploy the Azure App, and discuss why the application doesn’t work right away

For this demonstration I will be deploying the web application through GitHub with Continuous Integration and Continuous Delivery (CI / CD).

To create a gitignore file I will execute the following command

dotnet new gitignore
To be sure that our secrets are not copied to github we will ignore our devcontainer.env file. Open the .gitignore file. To the very bottom of the file add the following line:
To be sure there are no line ending conflicts whether the developer is working on windows or any other operating system, create a new file to the root of the project called .gitattributes. The content of the .gitrattibutes file will need to have the following content:
* text=auto eol=lf
Now using a command prompt I will initialize a new git repository and upload it to github.
git init
git add .
git commit -a -m “Initial Commit”
gh auth login
(Specify, HTTPS, Yes for GitHub Credentails, and Web Browser)
gh repo create azure-app-config-key-vault-demo --public --source=. --remote=upstream
git push --set-upstream upstream master 
    1 – Go to to review the repository that you just created on GitHub.

    2 – Go to the Actions tab

    3 – Search for “Azure” and then press the configure button on the “Deploy a .NET Core app to an Azure Web App” action.

    4 – Follow the directions in that file to set your AZURE_WEBAPP_PUBLISH_PROFILE setting in the repositories secret settings using the publish profile that is available in the Azure Web Application Azure
    5 – Resource that you created earlier.

    6 – Set the AZURE_WEB_APP_NAME to the appropriate value.

    7 – Set the DOTNET_VERSION to 6.0.x

Here is a screen shot of my configured AZURE_WEBAPP_PUBLISH_PROFILE configured on my repository.

I got that by downloading the publish profile on the Azure App Resource
Here is what my azure-webapps-dotnet-core.yml file ended up looking like:
# This workflow will build and push a .NET Core app to an Azure Web App when a commit is pushed to your default branch.
# This workflow assumes you have already created the target Azure App Service web app.
# For instructions see
# To configure this workflow:
# 1. Download the Publish Profile for your Azure Web App. You can download this file from the Overview page of your Web App in the Azure Portal.
#    For more information:
# 2. Create a secret in your repository named AZURE_WEBAPP_PUBLISH_PROFILE, paste the publish profile contents as the value of the secret.
#    For instructions on obtaining the publish profile see:
# 3. Change the value for the AZURE_WEBAPP_NAME. Optionally, change the AZURE_WEBAPP_PACKAGE_PATH and DOTNET_VERSION environment variables below.
# For more information on GitHub Actions for Azure:
# For more information on the Azure Web Apps Deploy action:
# For more samples to get started with GitHub Action workflows to deploy to Azure:

name: Build and deploy ASP.Net Core app to an Azure Web App

  AZURE_WEBAPP_NAME: sw-app-config-key-vault-demo-001    # set this to the name of your Azure Web App
  AZURE_WEBAPP_PACKAGE_PATH: '.'      # set this to the path to your web app project, defaults to the repository root
  DOTNET_VERSION: '6.0.x'                 # set this to the .NET Core version to use

      - "master"

  contents: read

    runs-on: ubuntu-latest

      - uses: actions/checkout@v3

      - name: Set up .NET Core
        uses: actions/setup-dotnet@v2
          dotnet-version: ${{ env.DOTNET_VERSION }}
      - name: Set up dependency caching for faster builds
        uses: actions/cache@v3
          path: ~/.nuget/packages
          key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
          restore-keys: |
            ${{ runner.os }}-nuget-

      - name: Build with dotnet
        run: dotnet build --configuration Release

      - name: dotnet publish
        run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v3
          name: .net-app
          path: ${{env.DOTNET_ROOT}}/myapp

      contents: none
    runs-on: ubuntu-latest
    needs: build
      name: 'Development'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

      - name: Download artifact from build job
        uses: actions/download-artifact@v3
          name: .net-app

      - name: Deploy to Azure Web App
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
          app-name: ${{ env.AZURE_WEBAPP_NAME }}
          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
          package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
Click on Start Commit when you are sure that you have the secret setup in your repository and the azure-webapps-dotnet-core.yml file properly configured.

You can go to the Actions tab and watch the action run the build and deploy steps if you like.

When it is complete it should look something like this:

Return to your App Service Azure resource and try to browse the site. You will likely notice that it will not launch and give you an error similar to this:
When we review the logs we will see something like this:
So where do we start troubleshooting this? Well, remember that we set environment variables on our development container, so we will need to set those environment variables for our web application as well.

    1 – In the Web app select the “Configuration” blade. We are now going to add the same environment variables that we added to our devcontainer.env file earlier.

    2 – Add an application setting named APPCONFIG_CONNECTION_STRING. Set it to the same value as is working in your Development Container, and a custom type.

    3 – Add an application setting named ASPNETCORE_ENVIRONMENT environment variable and give it the value of Development.

Be sure to save and continue saving your changes. This will restart your app. However, when you review the log stream again you might notice that it is still not quite working yet.
Basically, what is going on here is that the application is running anonymously and therefore does not have any permission to the app configuration and key vault, and therefore can not download those settings. We will discuss what to do in the next section.

Configure the Web Application Identity and Key Vault to make the application work

There are a number of ways to address this issue. The bottom line is that you want the application to be run as an identity that has access to the App Configuration and Kev Vault resources that you created earlier. This demonstration will use a system assigned identity with role-based authorization. There are other methods to doing this such as doing a system assigned identity and giving explicit permissions / policies to the identity. Or using User Assigned identities and using Role Based Authorization, or using User Assigned identities and explicit permissions / policies to those identities. Again, for this demonstration we will be focusing on the system assigned identity with resource-based authorization.

Within the App Service resource go to the “Identity” blade

On the System assigned tab, click on the “On” slider and save the changes.

Doing this basically created a user account in your azure ad tenant. However, this is a specific user account for your App Service Application.
We must now add the identity to be able to download configuration and key vault secrets.

    1 – Browse to the app configuration resource that you created earlier in the azure portal.

    2 – Click on the “Access Control (IAM)” blade.

    3 – Click on the “Add role assignment” button

    4 – Select the “Reader” role and click on “Next”
    5 – On the Members tab, select to assign access to a “Managed Identity.”
    6 –Click the Select members button and select the applicable subscription, and then App Service as the managed identity. Select the identity for your app service and press select.
Click “Review and Assign”

To confirm the access you can click on check access and select Managed identity and select your app service identity to see that it has the “Reader” role.

Now we should add this identity to the key vault.

    1 – Browse to the Key Vault that you created earlier.

    2 – Go to “Access Control (IAM)” in there.

    3 – Add a role assignment again.

    4 – Select the “Key Vaults Secrets User” role

    5 – Select that you want to assign a managed identity and select add member.

    6 – Select the identity associated with your web application

    7 – Click Review and Assign again and reconfirm access

With this in place you would think that it is enough; however, it is not. We also need to configure our key vault to use Role-Based Access.

    8 – Click on the “Access Policies” blade within this Key Vault.

    9 – Select the “Azure role-based access control” Permission Model

    10 – Take note of the warnings. Click on “Save”.

Return to the App Service resource that you created earlier, and restart the application. You should notice that the logs are cleaner and that the application starts. Browse to the application and you should see it launch now.

However, you might also get this error after signing in.
If so, then browse to the Application Registration in the Azure Active Directory resource that you created earlier.

    1 – Click on the “Authentication” blade.

    2 – Click on the Add URI, and add the URI that it is complaining about being mismatched, and then click on “Save”

Your application should work now.

Configure the key vault to allow collaborators to download configuration and key vault secrets

Now that you have this set up. You are all set to continue to develop and push new changes along the way. However, the developers that you will collaborate with will need a way to access these secrets as well. At this point in time we setup the key vault to be access via Role-Based Authorization. Similarly our App Configuration is the same. You have a number of options.

To give them the minimal amount of access required (aside from access to the GitHub repo) then you would follow these steps to add them

      • Go to the App Configuration Azure Resource that you created earlier
      • Click on “Access control (IAM)”
      • Click on Add role assignment
      • Select the “Reader” role
      • Select the User, group or service principal option. Press the select members button, and select the collaborator
      • Click on Review and Assign
      • Go to the Key Vault Azure Resource that you created earlier
      • Click on the “Access control (IAM)” blade
      • Click on Add role assignment
      • Select the “Key Vault Secrets User” role
      • Select the User,. Groups or service principal option. Press the select members button, and select the collaborator
      • Click on Review and Assign
Once the collaborator has these roles, they will also need to be sure to do an “az login” from their command prompt. They will also need to configure their devcontainer.env file with the appropriate APPCONFIG_CONNECTION_STRING.

You may also want to consider giving these roles on a higher level such as the resource group, or even the subscription. Especially if these collaborators will be working on multiple projects with you. You may also want to consider giving them contributor rights so that if they have new app configurations they need for use in the code, then they can add those configurations and secrets.

In Summary

Keeping secrets out of source code is indeed an important step but can be difficult. However, when you consider that the basic concept is to set up a repository for the secrets and a common way for both applications and developers to access those configurations things will all flow from there.

Please keep in mind that this demonstration covered using Role-based authorization with Azure Key Vault and Azure App Configuration. We did have you change from “Vault access policy” to “Azure role-based access control”. Please keep in mind that we could have kept this to Vault access policy, and you could have added a policy for your application managed identity to have access to the vault. Similarly, you would need to add policies for each of your collaborators instead of roles. Furthermore, there is a concept known as “User assigned” identities for Web Apps. We could have also created some User assigned identity to run our Web application and then given that identity the appropriate roles and / or policies to access the key vault. Exactly how and which you do will greatly depend on your organization’s security requirements.

Github repo:

About Intertech

Intertech is a Software Development Consulting Firm that provides single and multiple turnkey software development teams, available on your schedule and configured to achieve success as defined by your requirements independently or in co-development with your team. Intertech teams combine proven full-stack, DevOps, Agile-experienced lead consultants with Delivery Management, User Experience, Software Development, and QA experts in Business Process Automation (BPA), Microservices, Client- and Server-Side Web Frameworks of multiple technologies, Custom Portal and Dashboard development, Cloud Integration and Migration (Azure and AWS), and so much more. Each Intertech employee leads with the soft skills necessary to explain complex concepts to stakeholders and team members alike and makes your business more efficient, your data more valuable, and your team better. In addition, Intertech is a trusted partner of more than 4000 satisfied customers and has a 99.70% “would recommend” rating.