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.
[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>();
});
}
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
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"]
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>();
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With