[Configuration in Azure Functions Series - Part 4] Azure App Configuration and Azure Key Vault
Tags: azurefunctions, csharp, netcore
Published: 2019-12-09 10:27:11

---
title: [Configuration in Azure Functions Series - Part 4] Azure App Configuration and Azure Key Vault
published: true
description: This is part four of a series exploring .NET Core configuration, with an emphasis on Azure Functions.   In this article, we look at using other configuration providers in your Azure Function project, specifically Azure App Configuration and Azure Key Vault.
series: Configuration in Azure Functions Series
tags: azure_functions, csharp, .net_core
  
cover_image: https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/bilbo-with-ring.jpg
canonical_url: https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault/
---

This article was originally published at [blogs.siliconorchid.com](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault/) on 1-Nov-2019


**This is part four of a series exploring *.NET Core* configuration, with an emphasis on *Azure Functions*.   In this article, we look at using other configuration providers in your *Azure Function* project, specifically *Azure App Configuration* and** ***Azure Key Vault***

> In [part 1 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part1-intro-and-aspnetcore-configuration/), we introduce the subject of configuration and review how *ASP.NET Core* configuration works.

> In [part 2 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part2-azure-functions-configuration/), we look at how configuration in *Azure Functions (v2)* works and talk about some of the issues.

> In [part 3 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part3-aspnet-in-functions/), we show how you could include *ASP.NET Core* configuration into an *Azure Function* project.
 
> In [part 4 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault/), we look at using other configuration services, specifically *Azure App Configuration* and *Azure Key Vault*

<br/>
<hr/>

## Overview

Back in part one of this series, we learned that *.NET Core* configuration is created from multiple sources called ***Configuration Providers*** and that these can be combined together in **Layers**.  

Because of the flexibility that this model provides us with, we can take advantage of increasingly specialised services.  In this final article of the series, we'll explore two such Azure services that we can integrate into our architecture: *Azure App Configuration* & *Azure Key Vault*


<br/>
<br/>
<hr/>

<a name="azureappconfiguration"></a>

## Azure App Configuration

You can read the official documentation here:  [Microsoft Documentation : What is Azure App Configuration?]
(https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview)

*Azure App Configuration* is a cloud service that is used to store non-secret configuration settings in a centralised location.  These configuration settings can then be shared between multiple applications, including a global context.

Usually, when researching how to use *ASP.NET Core* and *Azure Functions*, a vast majority of the documentation and examples will steer us into storing our configuration settings directly onto the host server (whether this is an Azure AppService or a traditional VM server).

Whilst there is absolutely nothing wrong with this option, for certain systems that comprise of many related, but separate, services ([for example, a globally distributed solution of *Azure Functions* spread across multiple Azure Regions](https://https://blogs.siliconorchid.com/post/coding-inspiration/global-scaling/part3-frontdoor/), this can lead to us having to enter copies of exactly the same configuration settings into multiple different places.   Usually, where we find duplication, we find a risk of errors being introduced.  

The official documentation for *Azure App Configuration* is really comprehensive and provides tutorials specific to *Azure Functions*, so  we should just go ahead and follow those guides: 

* [Microsoft Documentation : Azure App Configuration quickstart]
(https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-azure-function-csharp)

* [Microsoft Documentation : Quickstart: Create an ASP.NET Core app with Azure App Configuration
](https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-aspnet-core-app)

* [Microsoft Documentation : Quickstart: Create an Azure function with Azure App Configuration
](https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-azure-function-csharp)

<br/>
<br/>
<hr/>

<a name="azurekeyvault"></a>

![tomb of balin from lord of the rings](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/tomb-balin.jpg#shadow)

## Azure Key Vault

You can read the official documentation here: [Microsoft Documentation : What is Azure Key Vault?](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-overview)

*Azure Key Vault* complements *Azure App Configuration* by being the configurable and secure place that we should use for application secrets.

This option, in particular, is an interesting proposition, as it uses an *Azure Active Directory* to provide access control to secrets, from both users (i.e. developers) and resources (i.e. an App Service).  For example: 

* The built-in integration with Visual Studio means that if we are working on a project that requires significant security controls, we can perform tricks such as granting developers usage of credentials, without ever directly revealing them.

* We can explicitly grant access to a *Secret Setting*, by a specific Azure resource.  Maybe this could be useful to minimize the risk of a credential intended for our production environment, accidentally being used in a development/testing system (e.g. because of a cut/paste mistakes) etc.

The official documentation is good, but unlike with *Azure App Configuration*, there are no guides that are specific to *Azure Functions* - so we'll be stepping through some steps to demonstrate how we can integrate *Azure Key Vault* into a demo project.

You will most likely find these supporting documents helpful.

* [Microsoft Documentation : Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal
](https://docs.microsoft.com/en-us/azure/key-vault/quick-create-portal)

* [Microsoft Documentation : Getting Started with Azure Key Vault with .NET Core
](https://azure.microsoft.com/en-us/resources/samples/key-vault-dotnet-core-quickstart/)

* [Microsoft Documentation : Add Key Vault to your web application by using Visual Studio Connected Services
](https://docs.microsoft.com/en-us/azure/key-vault/vs-key-vault-add-connected-service)


<br/>

## Let's setup an Azure Key Vault!

This tutorial assumes that we already know how to:

* create new *Azure Functions* projects using our IDE of choice
* create new *Azure Functions* AppService in the Azure Portal
* publish our *Azure Functions* project to Azure.

<br/>
<br/>

#### 1) Create a new HTTP-Triggered Azure Function from the templates.

First, create a new HTTP-Triggered *Function* from the templates.   For the purpose of this demo, we can leave everything, including the project and function names, to their defaults (i.e. `Function1` etc).

<br/>
<br/>

#### 2) Add extension packages

We need to add the following NuGet packages - we can use the Visual Studio package manager, or edit the `.csproj` file manually like this:-

<pre data-line="2,3"><code class="language-xml">&lt;ItemGroup&gt;
    &lt;PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" /&gt;
    &lt;PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" /&gt;
    &lt;PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.29" /&gt;
  &lt;/ItemGroup&gt;
</code></pre>

<br/>
<br/>

#### 3) Create a new Resource Group in Azure

Using the Azure Portal,  create a new ***Resource Group*** to keep all of the parts of our demonstration together.   I used the name `SiliconVaultDemoRG`, but you can choose your own. 

<br/>
<br/>

#### 4) Create a new *Azure Functions* AppService in Azure.

Using the Azure Portal, create a new ***Function App*** resource.  I used the name `SiliconVaultDemoFunctionApp`, but you can choose our own.   Select the *Runtime Stack* to be `.NET Core`, the *Region* to be near to you, accept the automatically generated *StorageAccount*, and leave the *Plan Type* with the default of `Consumption Plan`.


![screenshot creating azure function appservice](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/vault-create-appservice.png#shadow)


<br/>
<br/>

#### 5) Set AppService to have a System-Assigned Identity

When the *AppService* has been provisioned, select the `Identity` option and enable the `System Assigned Identity`.    Make sure that we click `Save`.    This will register the AppService within an [Azure Active Directory](https://azure.microsoft.com/en-gb/services/active-directory/).  We'll be assigning this newly created identity to our *Azure KeyVault* resource in a few moments.

![screenshot appservice identity](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/vault-system-identity.png#shadow)

<br/>
<br/>

#### 6) Create a new *Azure Key Vault* resource in Azure.

* Using the Azure Portal, create a new *Azure Key Vault*.   I chose to use the name `SiliconVaultDemoKeyVault`, but you can choose your own.   Select a *Region* near to you and leave the pricing tier as `Standard`.   Note that this is a paid-for service, but depending on our usage, the costs are relatively negligible - we can check the costs [here](https://azure.microsoft.com/en-us/pricing/details/key-vault/).

* Don't click the `create` button just yet, and instead select the `Next: Access Policy` button.

![screenshot create key vault 1](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/vault-createvault1.png#shadow)


<br/>
<br/>


#### 7) Grant permission to the new AppService identity.

Whilst displaying the "Access Policy" view, we should see our own user-identity appear in the `current access policy` list (the account that you used to log into the Azure Portal).   We need to add in the identity of the *AppService* now.

* Click the `Add Access Policy` option.

![screenshot create key vault 2](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/vault-createvault2.png#shadow)

<br/>
<br/>

* Completely ignore the options for `Configure from template`, `Key Permissions` and `Certificate Permissions`.

* Click on the `Secrets Permission` dropdown and choose just the sub-options `Get` and `List`.

* Click the `Select Principle` option and in the dialogue that appears, search for the name of the *ServiceApp* that we created earlier.   For me, I added `SiliconVaultDemoFunctionApp` here.

* Click `Add` to save the new policy record. 

* Click `Review and Create` to create the new Key Vault resource (along with the settings).

![screenshot create key vault 3](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/vault-createvault3.png#shadow)

<br/>
<br/>

#### 8) Make a note of service address 

With the *Azure Key Vault* resource now provisioned, go ahead and open the new resource.

* Select `Overview` and look at the dialogue for a *DNS Name*.   For me, this value is `https://siliconvaultdemokeyvault.vault.azure.net/`.     Make a note of this, as we'll be using it in a few moments. 

<br/>
<br/>

#### 9) Create a new secret setting

* Next, Select `Secrets` option and click the `Generate/Import` button.

![screenshot create key vault 4](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/vault-createvault4.png#shadow)

<br/>
<br/>

* We need to create a new secret setting, so leave *Upload Options* set to `Manual`,  provide a *Name* of `our-secret` and provide a value of: 

`This is a secret from Key Vault`

* Leave all other settings at their default (i.e. don't set an expiration date), and go ahead and click the `Create` button.

<br/>
<br/>

#### 10) Add startup code

In our *Azure Function* project, we need to add startup code which tells our application how to connect to our new *Azure Key Vault*. 

* Create a new class in the project called `startup.cs`, which contains the following code (we will need to substitute the *Azure Key Vault* URL as necessary):

```csharp
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(Startup))]
namespace FunctionApp1
{

    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var config = new ConfigurationBuilder()
                   .AddAzureKeyVault($"https://siliconvaultdemokeyvault.vault.azure.net/")
                   .Build();

            var ourSecret = config["our-secret"];

            builder.Services.AddSingleton(ourSecret);
        }
    }
}
```

It is worth noting that although our example DI code, above, is deliberately crude, it does still demonstrate how we can go about retrieving the secret-settings just once (at instance startup), rather than repeatedly hitting the *Azure Key Vault* on each and every function operation (and unnecessarily driving up usage demand and costs, to that resource).

<br/>
<br/>

#### 11) Update the http-triggered function code
In the file `Function1.cs` replace the entire code with the following:

```csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace FunctionApp1
{
    public class Function1
    {
        private readonly string _ourSecret;


        public Function1(string ourSecret)
        {
            _ourSecret = ourSecret;
        }

        [FunctionName("Function1")]
        public  async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            return new OkObjectResult($"We retrieved the following value from Azure Key Vault :  {_ourSecret}");
        }
    }
}
```
<br/>
<br/>

#### 12) Login locally to "Az Functions" CLI

A cool feature of *Azure Key Vault* is that *Active Directory* users who have been granted permission to the *Key Vault*, can develop locally using the secrets stored in the vault.   This means that we don't need to specify those values, at all, in the `local.secrets.json` file.

We can read how to integrate Visual Studio at [Microsoft Documentation : Add Key Vault to your web application by using Visual Studio Connected Services](https://docs.microsoft.com/en-us/azure/key-vault/vs-key-vault-add-connected-service)

To make this security integration work between *Azure Key Vault* and the *Azure Functions* CLI, we first need to make sure that we are logged in.  Use the following command and enter the same credentials that we used in the Azure Portal:

```
az login
```

> You could add other users to the Azure Active Directory, and grant these different users (aka "principles") permissions to view the secrets.   That is beyond the scope of this article.

<br/>
<br/>

#### 13) Test our local development version.

Making a note of the appropriate HTTP-Triggered Url (for me, this was `http://localhost:7071/api/Function1`), we should see the secret configuration information pulled from the *Azure Key Vault* and displayed as an HTTP response, like this:

```
We retrieved the following value from Azure Key Vault :  This is a secret from Key Vault
```

<br/>
<br/>

#### 14)  Deploy code to AppService and test cloud version.
Use "right-click deployment" to publish the app to the *Azure Functions* AppService that we created earlier.     Using the appropriate URL (for me, this was `https://siliconvaultdemofunctionapp.azurewebsites.net/`), demonstrate that the deployed version also works.

<br/>
<br/>
<hr/>

![aragorn from lord of the rings](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/aragorn.jpg#shadow)

## Azure Key Vault References

You can read the official documentation here : [Microsoft Documentation : Use Key Vault references for App Service and Azure Functions
](https://docs.microsoft.com/en-gb/azure/app-service/app-service-key-vault-references) 

> With perfect timing, late in the writing process of these articles (Oct 2019), Microsoft announced that [*Key Vault References* in App Service and Azure Functions are now generally available
](https://azure.microsoft.com/en-us/updates/general-availability-of-key-vault-references-in-app-service-and-azure-functions/).

"References" are a convenient improvement over the previous approach (described in the previous section) as it means that we no longer have to explicitly add additional code into our application to read settings from *Azure Key Vault*.

Instead, we:

* continue to use an *Azure Active Directory* managed-identity for our application (as previously). 
* where we need to access a secret stored in *Azure Key Vault*, we can replace the AppService configuration item with a specially formed "Reference String".


You should carefully read the official documentation for  "Reference Strings" [here](https://docs.microsoft.com/en-gb/azure/app-service/app-service-key-vault-references#reference-syntax), as you are presented with a couple of requirements and a choice of string-style.

There are two ways to write a "Reference String", here are examples of both, based on the example earlier in this article:

```
@Microsoft.KeyVault(SecretUri=https://siliconvaultdemokeyvault.vault.azure.net/secrets/our-secret/ec96f020xxxxxxxxxxxxxxxxxxxxxxxx)


@Microsoft.KeyVault(VaultName=https://siliconvaultdemokeyvault.vault.azure.net;SecretName=our-secret;SecretVersion=ec96f020xxxxxxxxxxxxxxxxxxxxxxxx)
```

<br/>
<br/>

The Azure Portal provides a convenient "cut+paste" facility, which you may find a convenient option.   We can find this screen by clicking, first on the `name` of the secret and then clicking a second time on the `version`. 

![azure-key-vault-secret-version](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/azure-key-vault-secret-version.png#shadow)

<br/>
<br/>



> It doesn't appear that *Azure Key Vault References* can be used for local development.  There is no obvious place where the reference string could be used, so we need to stick to using `local.settings.json` as usual.   This exact [question has been asked on GitHub](https://github.com/MicrosoftDocs/azure-docs/issues/26874) quite some time ago, during the beta phase, but at time of writing remains unanswered.  I'm sure this will be a useful feature that gets added in the future.

<br/>
<br/>
<hr/>

![galladriel from lord of the rings](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/galladriel-farewell.jpg#shadow)

## That's all

So, we're finally at the end of the series.  If you've managed to read all the way through - congratulations! This series has taken a surprising amount of time to put together, so I really hope that this information is helpful to someone!   If you have found it useful, please share this on social media, that way we can increase the chance of others in the developer community possibly finding the answers they've been looking for.


## Disclosure

No third party (i.e. Microsoft) compensates me for my promotion of their services in any way.


## Thumbs Up
A big thank you to Microsoft [~~Cloud Advocate~~ Azure Functions PM](https://twitter.com/nthonyChu/status/1184204419593916417),  &nbsp;  [Anthony Chu](https://anthonychu.ca/) for volunteering his time and literally burning the midnight oil to provide a technical review.  Some of the stuff I waded into was out of my depth and I really appreciated a voice from within Microsoft to help me out.

Thanks to Twilio Evangelist [Layla Porter](https://twitter.com/laylacodesit?lang=en) for supporting me once again, with her document-reviewing talents.



## Further reading

* [Microsoft Documentation : Configuration in ASP.NET Core
](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-3.0)

* [Github issue *"When using a FunctionsStartup class, settings are not read from the correct directory"*](https://github.com/azure/azure-functions-host/issues/4517) with fix, and mention from @fabiocav that application-level configuration is planned to be supported.


* [GitHub issue *"Load custom configuration file at startup"*](github.com/azure/azure-functions-dotnet-extensions/issues/17), which presents a way to locate the path for loading a config file.


* [GitHub Issue : Questions about local.settings.json / configuration files with Azure Functions](https://github.com/Azure/azure-functions-host/issues/4597).


* [GitHub Issue : Rename default appsettings.json file to local.settings.json](https://github.com/Azure/azure-functions-core-tools/issues/122) - indicates that Azure Functions historically used "appsettings.json" but renamed to "local.settings.json"

* [GitHub Issue : local.settings.json in .gitignore
](https://github.com/Azure/azure-functions-core-tools/issues/925) -  a discussion about the various merits and confusions related to the local.settings.json file

* [GitHub Issue : Perhaps we shouldn't include local.settings.example.json](https://github.com/Azure-Samples/function-image-upload-resize/issues/9) - a discussion about the merits of having a separate `local.settings.example.json` file