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

History

  • 2025-11-23 Updated to .NET 10, Azure functions V4, Azurite
  • 2021-03-07 Update packages and using DefaultAzureCredential for Azure Key vault access
  • 2020-10-23 Updated Azure Functions Configuration

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",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "ASPNETCORE_ENVIRONMENT": "Development",
    //"AZURE_TENANT_ID": "your tenant",
    // To use the key vault in local debug, the Firewall needs to allow this
    //"AzureKeyVaultEndpoint": "your azure ad tenant"
    "AzureKeyVaultEndpoint": ""
  },
  "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>net10.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <UserSecretsId>222f37ac-e563-4ba8-8e33-ee799c456135</UserSecretsId>
    <OutputType>Exe</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.23.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.51.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="2.50.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.11.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.3.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.1.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" />

    <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.4.0" />
    <PackageReference Include="Azure.Identity" Version="1.17.1" />
    <PackageReference Include="Azure.Security.KeyVault.Certificates" Version="4.8.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.0" />
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.0" />
  </ItemGroup>

  <ProjectExtensions><VisualStudio><UserProperties host_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>

</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 Azure.Identity;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyAzureFunctions;
using MyAzureFunctions.Activities;
using System.Reflection;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

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);
    });

var keyVaultEndpoint = builder.Configuration["AzureKeyVaultEndpoint"];

if (!string.IsNullOrEmpty(keyVaultEndpoint))
{
    // using Key Vault, either local dev or deployed
    builder.Configuration
        .SetBasePath(Environment.CurrentDirectory)
        .AddAzureKeyVault(new Uri(keyVaultEndpoint), new DefaultAzureCredential())
        .AddJsonFile("local.settings.json", optional: true)
        .AddEnvironmentVariables();
}
else
{
    // local dev no Key Vault
    builder.Configuration
        .SetBasePath(Environment.CurrentDirectory)
        .AddJsonFile("local.settings.json", optional: true)
        .AddUserSecrets(Assembly.GetExecutingAssembly(), optional: true)
        .AddEnvironmentVariables();
}

builder.Build().Run();

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

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace MyAzureFunctions.Activities;

public class MyActivities
{
    private readonly MyConfiguration _myConfiguration;
    private readonly MyConfigurationSecrets _myConfigurationSecrets;
    private readonly ILogger<MyActivities> _logger;

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

    [Function(Constants.MyActivityOne)]
    public string MyActivityOne([ActivityTrigger] string name)
    {
        _logger.LogInformation("Activity {myActivityOne} {name} {myConfigurationName} {myConfigurationSecretsMySecretOne} amount of retries: {myConfigurationAmountOfRetries}.",
            Constants.MyActivityOne, name, _myConfiguration.Name, _myConfigurationSecrets.MySecretOne, _myConfiguration.AmountOfRetries);

        return $"{Constants.MyActivityOne} {name} {_myConfiguration.Name} {_myConfigurationSecrets.MySecretOne} amount of retries: {_myConfiguration.AmountOfRetries}.";
    }

    [Function(Constants.MyActivityTwo)]
    public string MyActivityTwo([ActivityTrigger] string name)
    {
        _logger.LogInformation("Activity {myActivityTwo}  {name} {_myConfiguration.Name}.",
            Constants.MyActivityTwo, name, _myConfiguration.Name);

        return $"{Constants.MyActivityTwo} {name} {_myConfiguration.Name}!";
    }
}

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

With this, there 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

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

12 comments

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

  2. Pat Long's avatar
    Pat Long · · Reply

    I have read 2 or 3 stackoverflow questions and at at least 2 blog posts about how to get my local.settings.json working in my V3 AF. None of them worked. My dependency was always null. Then I came across your post. Thank you

    1. damienbod's avatar

      thanks for the comment, nice to know that it helped someone.

      Greetings Damien

  3. ernieboy's avatar
    ernieboy · · Reply

    Thanks Damien, this helped me a great deal too about keeping secrets out of source control.

    1. damienbod's avatar

      Hi ernieboy

      Thanks!

      Greetings Damien

  4. Tsahi Asher's avatar
    Tsahi Asher · · Reply

    The general recommendation is *not* to commit local.settings.json, since it may contain connection strings and other sensitive data.

    1. damienbod's avatar

      Hi Tsahi yes you should not commit secrets to any file or anywhere in a github repo. using a hidden file inside your github repo is not a good idea idea as I have experienced this pushed to repos with secrets in it. I recommend using user secrets for development and Azure Key vault for production and to remove all secrets from the github repo (including hidden or non committed files) This is also how ASP.NET Core recommends this. Greetings Damien

  5. hsadjdsjkuf's avatar
    hsadjdsjkuf · · Reply

    This doesnt seem to work for process isolated azure functions. Have you considered using updating the guide to reflect the difference in the configuration?

    1. damienbod's avatar

      I haven’t try the latest isolated functions yet, will look at this soon. Greetings Damien

  6. noontz's avatar

    That’s an awful lot of code for something that can be achieved in 4 lines 😉

    https://stackoverflow.com/a/75370617/2050637

  7. Unknown's avatar

    […] Azure Functions Configuration and Secrets Management […]

Leave a reply to ernieboy Cancel reply

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