Search code examples
c#azureazure-active-directoryazure-keyvaultazure-app-configuration

Azure Key Vault .NET Core 3.1 Web API Can't Access Secrets


I have a .NET Core 3.1 Web API project in which I'm trying to wire up Azure App Config. I have it working in a couple other .NET Framework projects just fine, but when I try to implement it in a Core 3.1 project, I am able to read unencrypted values from the App Config if the App Cong only contains unencrypted values, but get an exception whenever my App Config contains any reference to any Azure Key Vault secrets.

So far, I am just proving this out with a unit test project within the API solution. Here's the code:

namespace WebApi.Test.Integration.Settings
{
    public abstract class SettingsTestBase
    {
        protected SettingsTestBase()
        {
            Environment.SetEnvironmentVariable("Azure_Tenant_Id", "my-tenant-id");

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        }
    }
    
    public class SettingsTests : SettingsTestBase
    {
        [Fact]
        public void SettingsRequest_ReturnsValidSettings()
        {
            var config = GetConfiguration("https://my.keyvault.url.net");

            var setting = config["my-keyvaultvalue-v1"] ?? "Hello world!";

            Assert.NotNull(setting);
            Assert.NotEqual(string.Empty, setting);
            Assert.NotEqual("Hello world!", setting);
        }

        private IConfigurationRoot GetConfiguration(string uri)
        {
            var azureCred = new DefaultAzureCredential();
            var chainedCred = new ChainedTokenCredential(azureCred);
            var builder = new ConfigurationBuilder();

            //The optional:true parameter for AddAzureAppConfiguration does not work, as of AzureAppConfiguration 3.0.1, 
            //specifically for the KeyVaultReferenceException we're experiencing. However, this would only gracefully not
            //load our key vault secrets, not solve the problem we're having with retrieving secrets.
            //https://github.com/Azure/AppConfiguration-DotnetProvider/issues/136
            builder.AddAzureAppConfiguration(options =>
                options.Connect(new Uri(uri), chainedCred), optional: true);

            var config = builder.Build();

            return config;
        }
    }
}

Packages I have included so far:

Azure.Identity -v 1.1.1
Microsoft.Azure.KeyVault -v 3.0.5
Microsoft.Azure.Services.AppAuthentication -v 1.5.0
Microsoft.Extensions.Configuration.AzureAppConfiguration -v 3.0.1
Microsoft.Extensions.Configuration.AzureKeyVault -v 3.1.5

Here's what I get when I run the test:

 WebApi.Test.Integration.Settings.SettingsTests.SettingsRequest_ReturnsValidSettings
   Source: SettingsTests.cs
   Duration: 5 sec

  Message: 
    Microsoft.Extensions.Configuration.AzureAppConfiguration.KeyVaultReferenceException : No key vault credential configured and no matching secret client could be found.. ErrorCode:, Key:my-keyvaultsecretvalue-v1, Label:, Etag:xxxxxxxxxxxxxxxxxxxxxxxxx, SecretIdentifier:https://my.keyvault.url.net/secrets/my-keyvaultsecretvalue-v1
    ---- System.UnauthorizedAccessException : No key vault credential configured and no matching secret client could be found.
  Stack Trace: 
    AzureKeyVaultKeyValueAdapter.ProcessKeyValue(ConfigurationSetting setting, CancellationToken cancellationToken)
    AzureAppConfigurationProvider.ProcessAdapters(ConfigurationSetting setting, CancellationToken cancellationToken)
    AzureAppConfigurationProvider.SetData(IDictionary`2 data, CancellationToken cancellationToken)
    AzureAppConfigurationProvider.LoadAll(Boolean ignoreFailures)
    AzureAppConfigurationProvider.Load()
    ConfigurationRoot.ctor(IList`1 providers)
    ConfigurationBuilder.Build()
    SettingsTests.GetConfiguration(String uri) line 91
    SettingsTests.SettingsRequest_ReturnsValidSettings() line 60
    ----- Inner Stack Trace -----
    AzureKeyVaultSecretProvider.GetSecretValue(Uri secretUri, CancellationToken cancellationToken)
    AzureKeyVaultKeyValueAdapter.ProcessKeyValue(ConfigurationSetting setting, CancellationToken cancellationToken)

Solution

  • Key Vault access is not being configured.

    Try calling:

    builder.AddAzureAppConfiguration(options =>
      {
        options.Connect(new Uri(uri), chainedCred);
        options.ConfigureKeyVault(kv => kv.SetCredential(chainedCred));
      }, optional: true);
    

    chainedCred needs to be for a principal that has access to the referenced Key Vault.

    Or, if the reason that you haven't configured Key Vault is because you do not want the secrets, then the AzureAppConfiguration options will need to be set up so that only settings which do not reference Key Vault are queried.