Setup
I'm running a .NET 6 web app inside an Azure Container App and accessing Azure Key Vault for secrets and connection strings. Dependency Injection works fine for injecting my custom Key Vault client (wrapper of Azure.Security.KeyVault.Secrets.SecretClient), and I can successfully retrieve secrets after Build() (even from within Program.cs).
Problem
I need to fetch a connection string from Key Vault before Build() so I can pass it to a service constructor when registering dependencies. The SecretClient.GetSecret(keyName) call fails at this point.
I don't face the same problem when I run locally.
Logs
When the Container app is trying to activate the revision (and runs the Program.cs), I see this error from the Container app Log stream:
What I've Tried
- Ensuring Managed Identity is correctly assigned to the Container App.
- Confirming Key Vault permissions (it works later, so permissions shouldn't be the issue)
Question
How can I securely retrieve a secret before calling Build() in a .NET 6 containerized web app? Or is there a better pattern for handling this scenario?
Any insights would be greatly appreciated!
Code
public class KeyVaultService : IKeyVaultService
{
private readonly SecretClient _secretClient;
public KeyVaultService(string keyVaultName)
{
_secretClient = new SecretClient(new Uri($"https://{keyVaultName}.vault.azure.net"), new DefaultAzureCredential());
}
public string GetSecret(string keyName)
{
KeyVaultSecret secret = _secretClient.GetSecret(keyName);
return secret.Value;
}
}
public class Program
{
public static void Main(string[] args)
{
WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);
// ... configuring logging, etc ...
var keyVault = new KeyVaultService(keyVaultName);
// this is where it fails, but only in the Container app
// locally works fine.
string conn = keyVault.GetSecret("ConnectionString");
// registering a service that needs connectionString in its constructor.
var app = builder.Build();
// after Build() the Key Vault works fine.
keyVault = new KeyVaultService(keyVaultName);
conn = keyVault.GetSecret("ConnectionString");
// omitting unrelated code, like app.Run()
}
}
UPDATE
I tried adding the Key Vault to Configuration and does not work in my Azure Container App (works locally though).
From logs I noticed that before Build() the builder.Configuration["ConnectionString"] returns null or empty string, so I guess that Key Vault was not loaded as a provider.
WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddAzureKeyVault(XXXXX, new DefaultAzureCredential());
builder.ConfigureDatabase(builder.Configuration["ConnectionString"]);
var app = builder.Build();
