Skip to content

Main Index

Dr. Neil's Notes

Software > Coding

Using Azure Key Vault in .NET applications

Prerequisites

If you want to use the code from this Note you will need an Azure account, and the .NET SDK.

The code shown here is built and tested with the .NET 7.0 SDK.

Introduction

Building applications often requires calling external services that provide information, or perform functions. In several other examples in the coding sections of these Notes external services have been used, for example the ConsoleWeather and dotnetPiPictureFrame both use the OpenWeather service. These services require SecretKeys that connect you, and the application, consumption of the service. Often this is for billing, or to ensure that the service is not abused.

It is important you keep these Keys secret so that other people do not build software that pretends to be your application, and you end up paying for the service being used by someone else's software. To maintain a higher level of security it might be required that the keys be changed (or rotated) on a regular basis. The application you build should not need to be recompiled, or redeployed when you change the secret keys.

Microsoft Azure provides the Azure KeyVault to manage, maintain, and store your keys. Amazon has SecretsManager, for the same purposes.

These services are a great way to keep secret keys out of your code, and local configuration. When you deploy code to Azure, or AWS, the secrets can be made available to those environments.

In this Note I am going to demonstrate the use of Azure Key Vault in a .NET client application. To secure the access to the Key Vault a local certificate is going to be required, and installed, on the machine where the application is running. Without the certificate installed on the computer, the code will fail to authenticate to the Azure Key Vault, and be unable to get the Secret Keys to access the services.

Creating the certificate

To get started you will need to create a certificate. For this example I am creating a local certificate using PowerShell. This is fine for hobby projects. For a commercial product in production, you will want to use a certificate that has a trusted root, many online services exist for this.

To create a certificate yourself, on a Windows machine, you can use the following PowerShell script.

$certname = Read-Host -Prompt "Enter your certificate name"
$certPwd = Read-Host -Prompt "Enter a password for the privatekey"

$cert = New-SelfSignedCertificate -Subject "CN=$certname" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256

Export-Certificate -Cert $cert -FilePath "..\$certname.cer"   

$mypwd = ConvertTo-SecureString -String $certPwd -Force -AsPlainText  

Export-PfxCertificate -Cert $cert -FilePath "..\$certname.pfx" -Password $mypwd   

Setup the Azure Key Vault

In the Azure Portal create a new Microsoft Key Vault resource. You can do this in the Azure CLI with the following command, change the name to the name you want, and the resource group to the resource group you want, as well as the region, or location.

az keyvault create --name "<your-unique-keyvault-name>" --resource-group "myResourceGroup" --location "EastUS"

You want the Permission Model to be Azure role-based access control

In the portal you can set some secret keys, with a Name and a Value. You can also do this from the Azure CLI with the following script.

$vaultName = Read-Host -Prompt "Enter your key vault name"
$secretName = Read-Host -Prompt "Enter your secret name"
$secretValue = Read-Host -Prompt "Enter your secret value"

$Secret = ConvertTo-SecureString -String $secretValue -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $vaultName -Name $secretName -SecretValue $Secret

Setup an Azure AD application to access the Vault

To access the secrets from a client application, the client application will need to have the correct role, as defined in the RBAC (role-base access control).

In the Azure Portal, navigate to an Azure Active Directory that you can administrate. If you do not have an Azure Active Directory resource, you can create one, however this is beyond the scope of this Note.

In the App registrations section, create a New registration, it is useful to name this the same as your client application name. Ensure the application registration is for Mobile and desktop applications, meaning the redirect URL should be something like this https://login.live.com/oauth20_desktop.srf Once you have registered a new application, head to the Certificates and secrets section in the portal and Upload the certificate created in the previous step.

Then return to the Key Vault adminstration section in the portal and select the Access Control (IAM) section. Add a Role Assignment for Key Vault Secrets User, in order that the application can access the secret values. Then in the Members section, in Assign access to, select User, group, or service principal, then click Select Members, this will show a list of the AD users. To see the application, just created, type the application name in the search box. This will enable the application to access the Key Vault. Review and Assign the new role.

Code to access the Key Vault

In order that a client .NET application can access the KeyVault secrets, it will need to authenticate a the Application with the certificate. The VaultInfo class here provides the fields required for this to work.

public class VaultInfo
{
    public required string Thumbprint { get; set; }
    public required string VaultUrl { get; set; }
    public required string ClientId { get; set; }
    public required string TenantId { get; set; }
}

  • The Thumbprint is the thumbprint for the installed certificate to access the application.
  • The VaultUrl is the url of the KeyVault.
  • The ClientId and TenantId are the client and tenant Id for the AD application.

This fields in this VaultInfo class can easily be read from a json file, such as this.

{
    "Thumbprint": "12345678901234567890",
    "VaultUrl": "https://mysecrets.vault.azure.net/",
    "ClientId": "eeeeeeee-0000-0000-0000-aaaaaaaaaaaa",
    "TenantId": "eeeeeeee-0000-0000-0000-aaaaaaaaaaaa"
}

This json can be read into a VaultInfo object as shown below

string jsonString = File.ReadAllText(vaultFile);
vault = JsonSerializer.Deserialize<VaultInfo>(jsonString)!;

Read the certificate from the thumbprint as follows.

X509Store store = new (StoreName.My, StoreLocation.CurrentUser);
try
{
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
    if (col == null || col.Count == 0)
    {
        throw new Exception("ERROR: Valid certificate not found");
    }
    return col[0];
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    return null;
}
finally
{
    store.Close();
}

Given the certificate has been found from the thumbprint, the value for a secret key can be read from the KeyVault as follows.

TokenCredential credential = new ClientCertificateCredential(vault.TenantId, vault.ClientId, clientAssertionCertPfx);
var keyVaultSecretClient = new Azure.Security.KeyVault.Secrets.SecretClient(new Uri(vault.VaultUrl), credential);

var val = await keyVaultSecretClient.GetSecretAsync(secretNode);
return val.Value.Value;

Conclusions

Storing secret keys in application code, or config files, is a bad practice. It is not secure, requires the application is redeployed if the key needs to be changed, and makes it hard to manage all the different secrets and passwords your different applications use.

Services like Azure Key Vault, or AWS Secrets Manager, centralize the management of keys. When you are building a client application to run on a device, be it a personal computer, or an IOT type of device like a Raspberry Pi, you can install certificates on those devices, that enable the application to authenticate with Azure Key Vault and get the secret keys needed at run time.


Last update: May 18, 2024 05:34:37
Created: July 22, 2023 04:46:34
Authors: Neil Roodyn