Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Net core Key vault configuration using Azure.Security.KeyVault.Secrets

I have found out it is easy to connect to Azure KeyVault using Managed Identity. The documentation shows how to do it :

             var azureServiceTokenProvider = new AzureServiceTokenProvider();
            var keyVaultClient = new KeyVaultClient(
                new KeyVaultClient.AuthenticationCallback(
                    azureServiceTokenProvider.KeyVaultTokenCallback));

            config.AddAzureKeyVault(
                $"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
                keyVaultClient,
                new DefaultKeyVaultSecretManager());
        

Then I realized it requires the package Microsoft.Azure.KeyVault which is deprecated. So I'm struggling to figure out how to do the above with SDK 4. All the documentation I find is related to SDK 3.

enter image description here

[EDIT] I have found out the following code works to get the azure KeyVault Secret using Managed Identiy with SDK 4. However I can't see how to add this to my configuration. It used to be done with config.AddAzureKeyVault() from the Microsoft.Extensions.Configuration.AzureKeyVault Package however it is not compatible with the SDK 4 SecretClient:

  return Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((context, config) =>
                {
                    var azureCredentialOptions = new DefaultAzureCredentialOptions();
                
                  
                    var credential = new DefaultAzureCredential(azureCredentialOptions);
                    var secretClient = new SecretClient(new System.Uri("https://mykeyvault.vault.azure.net/"), credential);
                    var secret = secretClient.GetSecret("StorageConnectionString");
                    config.AddAzureKeyVault()                 
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
        }
like image 716
Sam Avatar asked Jun 21 '20 18:06

Sam


4 Answers

Latest working solution with version 4 library. My stack is .netcore 3.1 and I am using it inside an Azure Web App to access a secret from Azure KeyVault.

First thing first - go through this MS Doc link

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
//..........

 var kvUri = "https://YOURVAULTNAME.vault.azure.net/";
 var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
 KeyVaultSecret secret = client.GetSecret("SECRETNAME");
                       // Can also use await.....GetSecretAsync()      

 this.ConnectionString = secret.Value.ToString();
 \\thats my internal variable, secret.Value.ToString() is required value

I assume here that you have

  1. Created keyVault in Azure
  2. created a Managed identity in App Service(Using 'Identity' option in app service)
  3. Added above identity in Azure KeyVault('Access policies' option)
like image 94
Sumer Avatar answered Oct 27 '22 17:10

Sumer


As it turned out, I found the proper way to do it with SDK 4. I had to install the package azure.extensions.aspnetcore.configuration.secrets and then the code is simply :

   var credential = new DefaultAzureCredential();
               
   config.AddAzureKeyVault(new System.Uri("https://mykv.vault.azure.net/"), credential);

then to use it

configuration["StorageConnectionString"]
like image 30
Sam Avatar answered Oct 27 '22 19:10

Sam


First thing is that Microsoft.Azure.KeyVault is not deprecated but replaced. Using the old nuget package is still a valid option.

I imagine in the future, the Microsoft.Extensions.Configuration.AzureKeyVault nuget package will use the new Azure.Security.KeyVault.Secrets package.

In my experience I would stick with the existing library and wait for future updates.

If you really want to use the Azure.Security.KeyVault.Secrets, you can implement your own custom configuration builder.

I had a look at the existing key vault configuration code on github and here is a simplified/modified version that you could use.

First install these nuget packages Azure.Identity and Azure.Security.KeyVault.Secrets.

The new key vault secrets package uses IAsyncEnumerable so you need to update your project to target C#8.0: update you csproj file with <LangVersion>8.0</LangVersion>.

Azure Key Vault Secret configuration code:

public interface IKeyVaultSecretManager
{
    bool ShouldLoad(SecretProperties secret);

    string GetKey(KeyVaultSecret secret);
}

public class DefaultKeyVaultSecretManager : IKeyVaultSecretManager
{
    public bool ShouldLoad(SecretProperties secret) => true;

    public string GetKey(KeyVaultSecret secret)
        => secret.Name.Replace("--", ConfigurationPath.KeyDelimiter);
}

public class AzureKeyVaultConfigurationProvider : ConfigurationProvider
{
    private readonly SecretClient _client;
    private readonly IKeyVaultSecretManager _manager;

    public AzureKeyVaultConfigurationProvider(SecretClient client, IKeyVaultSecretManager manager)
    {
        _client = client ?? throw new ArgumentNullException(nameof(client));
        _manager = manager ?? throw new ArgumentNullException(nameof(manager));
    }

    public override void Load() => LoadAsync().ConfigureAwait(false).GetAwaiter().GetResult();

    private async Task LoadAsync()
    {
        var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        await foreach (var secretProperties in _client.GetPropertiesOfSecretsAsync())
        {
            if (!_manager.ShouldLoad(secretProperties) || secretProperties?.Enabled != true)
                continue;

            var secret = await _client.GetSecretAsync(secretProperties.Name).ConfigureAwait(false);
            var key = _manager.GetKey(secret.Value);
            Data.Add(key, secret.Value.Value);
        }

        Data = data;
    }
}

public class AzureKeyVaultConfigurationSource : IConfigurationSource
{
    public SecretClient Client { get; set; }

    public IKeyVaultSecretManager Manager { get; set; }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new AzureKeyVaultConfigurationProvider(Client, Manager);
    }
}

public static class AzureKeyVaultConfigurationExtensions
{
    public static IConfigurationBuilder AddAzureKeyVault(
        this IConfigurationBuilder configurationBuilder,
        SecretClient client,
        IKeyVaultSecretManager manager = null)
    {
        if (configurationBuilder == null)
            throw new ArgumentNullException(nameof(configurationBuilder));

        if (client == null)
            throw new ArgumentNullException(nameof(client));

        configurationBuilder.Add(new AzureKeyVaultConfigurationSource()
        {
            Client = client,
            Manager = manager ?? new DefaultKeyVaultSecretManager()
        });

        return configurationBuilder;
    }
}

You can now use this configuration builder in your project like that:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            var azureCredentialOptions = new DefaultAzureCredentialOptions();
            var credential = new DefaultAzureCredential(azureCredentialOptions);
            var secretClient = new SecretClient(new System.Uri("https://mykeyvault.vault.azure.net/"), credential);

            config.AddAzureKeyVault(secretClient);
        })
            .UseStartup<Startup>();
}
like image 35
Thomas Avatar answered Oct 27 '22 18:10

Thomas


For your info, if you're using Azure Key Vault secrets in your App Service or Azure Functions application settings, you don't have to add extra code to get the key vault value.

You just need to change your app settings values (in azure portal), with your key vault references.

For the steps, look at https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references

Setting example using key vault references: { "name": "DatabaseSettings:ConnectionString", "value": "@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/DatabaseConnectionSettingSecret/ec96f02080254fxxxxxxxxxxxxxxx)", "slotSetting": false }

But this doesn't work for a local development, instead you should use plain secret value. But for me it's okay, because your local development uses different secret value and you don't add your local.settings.json to source control.

like image 22
Albert Alfrianta Avatar answered Oct 27 '22 17:10

Albert Alfrianta