Azure Functions Configuration and Secrets Management

This post shows how to configure Azure Function projects so that no secrets are required in the local.settings.json or in the code. Secrets for the project are saved in the user secrets of the project, or in the app settings of the deployment. The deployment should/can use Azure Key Vault for the secrets and not the app.settings of the deployment (or key vault). The aim is to remove the secrets from the code and the local.settings.json file. I see this committed in many solutions with secrets.

Code: https://github.com/damienbod/AzureDurableFunctions

Posts in this series

The local.settings.json file can be used to add app settings for local development in your Azure Function project. In this file, are standard configuration values which are not secrets and this file can be committed to the git repository. In this demo, we added a MyConfiguration class with two values. Note that the configuration is not added inside the Values object. I prefer this.

local.settings.json

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "AzureWebJobsSecretStorageType": "Files",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
  },
  "MyConfiguration": {
    "Name": "Lilly",
    "AmountOfRetries": 7
  }
}

The Azure functions project requires the Microsoft.Extensions.Configuration.UserSecrets nuget package to support user secrets for local development.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
    <UserSecretsId>222f37ac-e563-4ba8-8e33-ee799c456135</UserSecretsId>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.2.2" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="3.1.0" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.7" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.5" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.5" />
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

In the secrets json file which is in your profile and not the source code, you can add the super secrets.

{
  "MyConfigurationSecrets": {
    "MySecretOne": "secret one",
    "MySecretTwo": "secret two"
  }
}

The Azure Functions project uses DI and so has a Startup class which inherits from the FunctionsStartup class. The configuration is setup using the ConfigurationBuilder and uses the optional Json files and the optional user secrets. It is important that these are optional. The configuration classes are added using the IOption interface.

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MyAzureFunctions;
using MyAzureFunctions.Activities;
using System;
using System.Configuration;
using System.Reflection;

[assembly: FunctionsStartup(typeof(Startup))]

namespace MyAzureFunctions
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var config = new ConfigurationBuilder()
               .SetBasePath(Environment.CurrentDirectory)
               .AddJsonFile("local.settings.json", true)
               .AddUserSecrets(Assembly.GetExecutingAssembly(), true)
               .AddEnvironmentVariables()
               .Build();

            builder.Services.AddSingleton<IConfiguration>(config);

            builder.Services.AddScoped<MyActivities>();

            builder.Services.AddOptions<MyConfiguration>()
                .Configure<IConfiguration>((settings, configuration) =>
                {
                    configuration.GetSection("MyConfiguration").Bind(settings);
                });

            builder.Services.AddOptions<MyConfigurationSecrets>()
                .Configure<IConfiguration>((settings, configuration) =>
                {
                    configuration.GetSection("MyConfigurationSecrets").Bind(settings);
                });
        }
    }
}

The configurations can then be used like any ASP.NET Core project.

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace MyAzureFunctions.Activities
{
    public class MyActivities
    {
        private readonly MyConfiguration _myConfiguration;
        private readonly MyConfigurationSecrets _myConfigurationSecrets;

        public MyActivities(IOptions<MyConfiguration> myConfiguration, 
            IOptions<MyConfigurationSecrets> myConfigurationSecrets)
        {
            _myConfiguration = myConfiguration.Value;
            _myConfigurationSecrets = myConfigurationSecrets.Value;
        }

When configuring this in Azure, the app settings need to be added to the Azure APP service hosting the functions.

With this, they is no need to add secrets anymore to the local.settings.json file of the Azure Function projects.

Links:

https://docs.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings

https://docs.microsoft.com/en-us/azure/azure-functions/durable/

https://github.com/Azure/azure-functions-durable-extension

https://damienbod.com/2019/03/14/running-local-azure-functions-in-visual-studio-with-https/

Microsoft Azure Storage Explorer

Microsoft Azure Storage Emulator

Install the Azure Functions Core Tools

NodeJS

Azure CLI

Azure SDK

Visual Studio zure development extensions

One comment

  1. […] Azure Functions Configuration and Secrets Management – Damien Bowden […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: