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:
- 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
-
— A Resource Group
— An App Configuration
— A Key Vault
— An App Service Plan
— An App Service Web App
-
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.
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
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 @ https://portal.azure.com/
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
-
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
Create Azure Resources
All of these items will be created using the Azure Portal @ https://portal.azure.com/.
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 https://login.microsoftonline.com/.
-
-
- Click on Create and select Key Value
- The Key will be: “AzureAd:Instance” (without the quotes)
- The Value will be: “https://login.microsoftonline.com/” (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
-
-
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
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.
-
-
- devcontainer.env
- devcontainer.env.example
-
Copy and paste the contents of each file to be the following
APPCONFIG_CONNECTION_STRING=Connection string from <appconfigurl>
ASPNETCORE_ENVIRONMENT=Development
In the devcontainer.env file replace “Connection string form
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.
echo $APPCONFIG_CONNECTION_STRING
echo $ASPNETCORE_ENVIRONMENT
To let your environment know who you are on Azure execute the following command
az login
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
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
Execute the following commands:
dotnet add package Azure.Identity
dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore
After this line of code…
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');
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 =>
{
azureAppConfigurationOptions.Connect(appConfigConnectionString)
.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
devcontainer.env
* text=auto eol=lf
git init
git add .
git commit -a -m “Initial Commit”
gh auth login
(Specify Github.com, 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 https://www.github.com/ 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.
# 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 https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?tabs=net60&pivots=development-environment-vscode
#
# 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: https://docs.microsoft.com/en-us/azure/app-service/deploy-github-actions?tabs=applevel#generate-deployment-credentials
#
# 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: https://docs.microsoft.com/azure/app-service/deploy-github-actions#configure-the-github-secret
#
# 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: https://github.com/Azure/Actions
# For more information on the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# For more samples to get started with GitHub Action workflows to deploy to Azure: https://github.com/Azure/actions-workflow-samples
name: Build and deploy ASP.Net Core app to an Azure Web App
env:
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
on:
push:
branches:
- "master"
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up .NET Core
uses: actions/setup-dotnet@v2
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Set up dependency caching for faster builds
uses: actions/cache@v3
with:
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
with:
name: .net-app
path: ${{env.DOTNET_ROOT}}/myapp
deploy:
permissions:
contents: none
runs-on: ubuntu-latest
needs: build
environment:
name: 'Development'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v3
with:
name: .net-app
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
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:
-
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.
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.
-
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.
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.
-
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
-
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.
-
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”
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
-
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: https://github.com/woodman231/azure-app-config-key-vault-demo
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. Blackslate Software 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 Blackslate Software 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, Blackslate Software is a trusted partner of more than 4000 satisfied customers and has a 99.70% “would recommend” rating.