1
votes

I want to use the Azure Key Vault Provider to populate my app's configuration. Using Microsoft.Azure.Functions.Extensions 1.1.0 in conjunction with Azure.Extensions.AspNetCore.Configuration.Secrets my code looks as follows:

local.settings.json

{
    "IsEncrypted": false,
    "Values": {
        "KeyVaultUri": "https://meh.vault.azure.net/",
        "TEST:SuperSecret": "secret-name-of-key-vault-entry"
    }
}

Startup.cs

[assembly: FunctionsStartup(typeof(Startup))]
namespace myNamespace
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddOptions<AppSettingsSecrets>()
                .Configure<IConfiguration>((cfgSection, cfg) => cfg.GetSection("TEST").Bind(cfgSection));
        }
    
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            var builtConfig = builder.ConfigurationBuilder.Build();
            var kvEndpoint = builtConfig["KeyVaultUri"];
            var cred = new ChainedTokenCredential(new ManagedIdentityCredential(), new AzureCliCredential()); 
            var opt = new AzureKeyVaultConfigurationOptions { ReloadInterval = TimeSpan.FromHours(24)};
            
            builder.ConfigurationBuilder
                .AddAzureKeyVault(new Uri(kvEndpoint), cred, opt)
                .SetBasePath(Environment.CurrentDirectory)
                .AddJsonFile("local.settings.json", optional: true)
                .AddEnvironmentVariables()
                .Build();
        }
    }
}

Functions.cs

namespace myNamespace
{
    public class SEC
    {
        private readonly IOptions<AppSettingsSecrets> _s;
        public SEC(IOptions<AppSettingsSecrets> s) => _s = s;

        [FunctionName(nameof(SEC))]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "sec")] HttpRequest req, ILogger log)
        {
            log.LogInformation(_s.Value.SuperSecret);
            return new OkObjectResult(true);
        }
    }
}

Now when I invoke

iwr http://localhost:7071/api/sec

What will be logged is the literal value of the secret name secret-name-of-key-vault-entry. Not the secret's value from the key vault.

It is definitely not an issue with the access policy, because previously I manually queried secrets from the same vault using the same user principal.

What am I missing? Any help is appreciated.

1

1 Answers

1
votes

I found a working solution on YouTube. Posting here so maybe others might benefit.

local.settings.json: secret config values NOT present in here

{
    "IsEncrypted": false,
    "Values": {
        "KeyVaultUri": "https://meh.vault.azure.net/",
    },
    "Settings": {
        "IsProd": false
    }
}

AppSettings.cs

namespace myNamespace
{
    public class AppSettings
    {
        public bool IsProd {get; set;}
        public string GraphCredential {get; set;} = string.Empty;
    }
}

Then in the key vault itself, register a secret with the name Settings--GraphCredential (two dashes!)

namespace myNamespace
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddOptions<AppSettings>()
                .Configure<IConfiguration>((cfgSection, cfg) => cfg.GetSection("Settings").Bind(cfgSection));
        }
    
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            var builtConfig = builder.ConfigurationBuilder.Build();
            var kvEndpoint = builtConfig["KeyVaultUri"];
            var cred = new ChainedTokenCredential(new ManagedIdentityCredential(), new AzureCliCredential()); 
            var opt = new AzureKeyVaultConfigurationOptions { ReloadInterval = TimeSpan.FromHours(24)};
            
            builder.ConfigurationBuilder
                .AddAzureKeyVault(new Uri(kvEndpoint), cred, opt)
                .SetBasePath(Environment.CurrentDirectory)
                .AddJsonFile("local.settings.json", optional: true)
                .AddEnvironmentVariables()
                .Build();
        }
    }
}