My GitHub repo shows how to retrieve secrets stored in an Azure Key Vault using a .NET Framework & .NET Core application. It demonstrates both pulling the secrets via middleware at startup time and dynamically when a page is loaded.
Onprem deployment

Onprem, you need to provide a way for the running application to access the Key Vault securly. This is accomplished via service principal provisioned in Azure Active Directory. This service principal is then granted access to the Key Vault. The application authenticates to Azure Active Directory using a X.509 certificate so that it can use the service principal to access the Key Vault.
Note: The application is written to pull the certificate from the cert:\LocalMachine\My
certificate store on the onprem server. If this is not the right location to get your certificate from, you will need to modify the code to pull the certificate from the correct location.
You will need to modify code similar to the below code to pull from the right store for your deployment.
var x509Store = new X509Store(StoreName.My,
StoreLocation.LocalMachine);
Azure deployment

In Azure, the process can be simplified by using a Managed Identity. The Managed Identity is granted access to the Key Vault & is assigned to the App Service so code running in the App Service can use it. The deployment script will set the Managed Identity client ID for you as part of deployment. This will override the values specified in the configuration files.
Note: This repo intentionally doesn’t access the secrets through the Azure App Service configuration so that it is portable between onprem & Azure. If you are only targeting Azure, you can store the secrets in the App Service configuration.
Note: You could still use the certificate-based authentication method to allow your application to authenticate with Azure AD instead of using Managed Identity. Managed Identity makes the process simpler, but is not required.
Disclaimer
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.NET Framework
The .NET Framework version of this application pulls the secrets from Key Vault when the web page is loaded. It does not have a default inversion of control container that pulls the secrets at startup time. Instead, it uses a custom implementation of the ConfigBuilder
to pull the certificate from the Windows certificate store to authenticate to Azure with & pull all the secrets from Key Vault.
The following NuGet packages are required to access Key Vault using .NET Framework (these will install some additional dependencies):
- Azure.Identity
- Azure.Security.KeyVault.Secrets
- Microsoft.Configuration.ConfigurationBuilders.Azure
If you look at the ./web-net-framework/Web.config
file, you can see the following configBuilder
section which tells teh custom CertificateAuthenticationAzureKeyVaultConfigBuilder
class how to authenticate with Azure Active Directory so it can use the service principal to access the Key Vault.
<configBuilders>
<builders>
<add name="KeyVault" mode="Greedy" vaultName="kv-keyvault-web-ussc-dev" enabled="true" certificateStoreName="My" certificateStoreLocation="LocalMachine" certificateThumbprint="a17d4362fbf40049bb4aa7eb465d082358c7878a" tenantId="72f988bf-86f1-41af-91ab-2d7cd011db47" clientId="9bfd1049-3cfe-4466-a684-2b5fb636b03e" type="web_net_framework.Services.CertificateAuthenticationAzureKeyVaultConfigBuilder, web-net-framework" />
</builders>
</configBuilders>
<appSettings configBuilders="KeyVault">
<add key="the-king-of-england" value="Elizabeth II" />
...
</appSettings>
You will notice that the appSettings
section of the Web.config
file has a value already for the-king-of-england
. Naturally, this value is wrong and we want to override it with the value from Key Vault. The Greedy
flag will override the value from the Web.config
withe the one from Key Vault if it was able to successfully authenticate & pull secrets.
Here is what the running application should look like if it was able to successfully authenticate with Azure Active Directory & pull secrets from Key Vault.

Onprem authentication with certificate
In the ./web-net-framework/Services/CertificateAuthenticationAzureKeyVaultConfigBuilder.cs
, we pull the certificate from the local store, authenticate with Azure AD, then pull the secrets that are needed. This custom class is needed because the default implementation of the AzureKeyVaultConfigBuilder
will try to use the DefaultAzureCredentials
class which will not work on the onprem server since it doesn’t have a managed identity nor does the service account running the app pool have access to Azure. Instead, we want to pull a certificate from the local store and authenticate with Azure AD.
protected override TokenCredential GetCredential()
{
StoreName storeName = (StoreName)Enum.Parse(typeof(StoreName), CertificateStoreName);
StoreLocation storeLocation = (StoreLocation)Enum.Parse(typeof(StoreLocation), CertificateStoreLocation);
var x509Store = new X509Store(storeName,
storeLocation);
x509Store.Open(OpenFlags.ReadOnly);
X509Certificate2 x509Certificate;
try
{
x509Certificate = x509Store.Certificates.Find(X509FindType.FindByThumbprint,
CertificateThumbprint,
validOnly: false)
.OfType<X509Certificate2>()
.Single();
}
catch (Exception ex)
{
throw new ArgumentException($"Unable to find certificate in cert:\\{CertificateStoreLocation}\\{CertificateStoreName} with thumbprint: {CertificateThumbprint}", ex);
}
var tokenCredential = new ClientCertificateCredential(TenantId,
ClientId,
x509Certificate);
return tokenCredential;
}
App Service with Managed Identity
Using the Managed Identity associated with the App Service, it much simpler to authenticate with Azure AD.
client = new SecretClient(new Uri(kvUri),
new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ManagedIdentityClientId = ConfigurationManager.AppSettings["Authentication:ManagedIdentityClientId"]
}));
.NET Core
Similarly, the .NET Core version of this application pulls the Key Vault secrets when the web page is loaded. However, because .NET Core already has a inversion of control container installed, most of the secrets are pulled at startup time. Only 1 secret is pulled at page load time to demonstrate how to pull secrets dynamically.
If you look at the ./web-net-core/appsettings.json
file, you can see the following app settings which will allow the application to authenticate with Azure Active Directory so it can use the service principal to access the Key Vault.
"KeyVaultName": "kv-keyvault-web-ussc-dev",
"Authentication": {
"AzureADApplicationId": "9bfd1049-3cfe-4466-a684-2b5fb636b03e",
"AzureADCertificateThumbprint": "539cd5afadb7b25b85cf90a78c261074a6db6445",
"AzureADDirectoryId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"ManagedIdentityClientId": ""
},
"IsHostedOnPrem": "true"
Here is what the running application should look like if it was able to successfully authenticate with Azure Active Directory & pull secrets from Key Vault.

Startup.cs code to pull all secrets as configuration values
The middleware allows us to pull all secrets from Key Vault at startup time and store them as configuration values that can be used throughout the application (look at the ./web-net-core/Program.cs
file).
builder.Configuration.AddAzureKeyVault(new Uri(kvUri), new ClientCertificateCredential(
builder.Configuration["Authentication:AzureADDirectoryId"],
builder.Configuration["Authentication:AzureADApplicationId"],
x509Certificate));