5

I've created an Entity Framework DbContext which I initialize in the Program (Startup.cs is not needed anymore in .NET 6). The connectionstring is dependent on a SQL password inside Azure Key Vault. So the registration of both Key Vault and DbContext are done in the Program.cs . But how do I retrieve the secret from KeyVault to put inside the connectionstring? I do not want to manually create a SecretClient instance here, but have it injected somehow...

I now have:

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddSecretClient(new Uri(builder.Configuration.GetSection("KeyVault:VaultUri").Value))
        .WithCredential(new DefaultAzureCredential());
});
builder.Services.AddDbContext<MyContext>(options =>
{
    // How to get an instance of SecretClient here via DI? I need to call the serviceClient.GetSecret("sql-password") here to put it inside the connectionstring
    // var sqlPassword = builder.Configuration.GetSection("sql-password").Value <-- also returns null
    var sqlPassword = "get-this-password-from-key-vault";
    options.UseSqlServer(string.Format(builder.Configuration.GetConnectionString("MyConnectionString"), sqlPassword));
});

I've read on several blogs that when you add the SecretClient to the Services, it should read all the secrets and add them to the builder.Configuration , meaning you should be able to read it like this:

var sqlPassword = builder.Configuration["sql-password"]

or

var sqlPassword = builder.Configuration.GetSection("sql-password").Value

Both of them return null . So I'm running out of options here. If anyone has a solution for this simple problem, I'm more than grateful. Thanks!

PS: I know for a fact the Key Vault is registered successfully; when I use the ServiceClient within a controller, I can successfully retrieve the secret.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Peter
  • 217
  • 1
  • 2
  • 8

1 Answers1

6

You can register a SecretClient a number of ways described at https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/extensions/Microsoft.Extensions.Azure/README.md. In this case, you could even instantiate a SecretClient, add it to the configuration builder, then use it directly. Or once registered to the confguration builder, refer to the configuration value you want that is stored in a SecretClient:

var builder = WebApplication.CreateBuilder(args);

var keyVaultEndpoint = new Uri(Environment.GetEnvironmentVariable("VaultUri"));
builder.Configuration.AddAzureKeyVault(keyVaultEndpoint, new DefaultAzureCredential());

// Add services to the container.
builder.Services.AddDbContext<MyContext>(options =>
{
    var sqlPassword = builder.Configuration["secret-password"];
    options.UseSqlite(string.Format(builder.Configuration.GetConnectionString("MyConnectionString"), sqlPassword));
});

In Key Vault, just add a secret named "secret-password" in this case.

Heath
  • 2,986
  • 18
  • 21
  • Thanks! Yes this did the trick! So I only added the SecretClient to the services, but to load the keyvault secrets into your configuration, you need to add the NuGet package Microsoft.Extensions.Configuration.AzureKeyVault , and then call the builder.Configuration.AddAzureKeyVault . Thank you so much! – Peter Feb 03 '22 at 06:57
  • 3
    For anyone finding this now `Microsoft.Extensions.Configuration.AzureKeyVault` is now deprecated as of 2Q2022, the replacement is now `Azure.Extensions.AspNetCore.Configuration.Secrets` – CajunCoding Jul 21 '22 at 23:12
  • I tried this and I am getting Azure.Identity.CredentialUnavailableException – roney Jan 19 '23 at 01:54
  • @roney do you have the azure.identity package installed? – Jeff Patton Feb 14 '23 at 04:13