To access an Azure Key Vault secret from your code, you must register your key vault as an application.

The steps are:

  1. Create the key vault
  2. Register the application with Azure Active Directory
  3. Add a Client Secret to the App Registration
  4. Add an Access Policy to the Key Vault
  5. Set Environment Variables
  6. Write the code

Create the key vault

First, you need to create a Key Vault in which to store your secrets. For instructions on how to create a Key Vault, see this article.

Register the application with Azure Active Directory

After creating a Key Vault, register the Key Vault with Azure Active Directory.

This article shows how to do this.

For our purposes, the most important pieces of information from the Application Registration are the  Application ID, which is sometimes called the Client ID.

You can find this on the Azure Active Directory "App registrations" blade. Search for your App Registration by name, as shown in Fig. 1.

kvc01-AppRegistration
Fig. 1

Record the Display name, the Application (client) ID) and the Directory (tenant) ID. You will need these later.

Add a Client Secret to the App Registration

Next, you will need to create a Client Secret within your Application Registration.

Within the App Registration, click the [Certificates & secrets] button (Fig. 2) to open the "Certificates & secrets" blade, as shown in Fig. 3

kvc02-CertificatesAndSecretsButton
Fig. 2

kvc03-CertificatesAndSecretsBlade
Fig. 3

To create a Client Secret, select the "Client secrets" tab and click the [New client secret] button (Fig. 4) to open the "Add a client secret" dialogue, as shown in Fig. 5.

kvc04-NewClientSecretButton
Fig. 4

kvc05-AddClientSecret
Fig. 5

At the "Description" field, enter a description of the secret (e.g., for which application are we generating a secret).

At the "Expires" dropdown, select how soon this secret will expire, requiring you to generate a new one.

When you finish completing the dialogue, click the [Add] button (Fig. 6) to return to the Application Registration" page, as shown in Fig. 7.

kvc06-AddButton
Fig. 6

kvc07-ClientsAndSecretsBlade
Fig. 7

Your newly created secret will display in the list on the "Client secrets" tab. Copy and save the "Value" column. After you navigate away from this page, you will no longer be able to view the Value.

Add an Access Policy to the Key Vault

An Access Policy tells Azure which users, applications, and services have access to Azure Key Vault and what actions they can take on the information stored in Key Vault. After you have registered the application, you will need to create an Access Policy in Azure Key Vault, providing the Application Registration access to the key vault.

To add an Azure Key Vault Access Policy, navigate to the Azure Portal, log in, and open the Azure Key Vault, as shown in Fig. 2.

kvc08-AzureKeyVault
Fig. 8

Click the [Access policies] button (Fig. 3) in the left menu to display the "Access Policies" blade, as shown in Fig. 4.

kvc09-AccessPoliciesButton
Fig. 9

kvc10-AccessPolicyBlade
Fig. 10

Click the [Add Access Policy] button (Fig. 5) to display the "Add access policy" dialogue, as shown in Fig. 6.

kvc11-AddAccessPolicyButton
Fig. 11

kvc12-AddAccessPolicyDialogue
Fig. 12

This dialogue provides a number of templates which preselect permissions to access and manage keys, secrets, and certificates in this Azure Key Vault. If you like, you can select one of these, as shown in Fig. 7.

kvc13-AccessPolicyTemplates
Fig. 13

Alternatively, you can specify each permission explicitly for keys, secrets, and certificates in this key vault. Fig. 8 shows how to select all permissions for managing secrets, which I will do for this demo.

When you have selected all the desired permissions, click the [Add] button (Fig. 8) to return to the "Add access policy" dialogue.

kvc14-SecretPermissions
Fig. 14

The next step is to give these permissions to the Application Registration. Click the link next to "Select principal" to open the "Principal" dialogue, as shown in Fig. 9.

kvc15-AddButton
Fig. 15

Search for the Application Registration by display name, select the Registration from the list, as shown in Fig. 10 and click the [Select] button to close the "Principal" dialogue and return to the "Add Access Policy" dialogue, as shown in Fig. 11.

kvc16-SelectPrincipalDialogue
Fig. 16

kvc17-AddAccessPolicy
Fig. 17

Finally, click the [Save] button (Fig. 12) to close the "Principal" dialogue and return to the "Access Policies" blade, as shown in Fig. 13. You will lose your changes if you fail to click the [Save] button before navigating

kvc18-SaveButton
Fig. 18

kvc19-AccessPoliciesBlade
Fig. 19

Set Environment Variables

The sample application below uses the DefaultAzureCredential class to authenticate the user. This class pulls information from the following environment variables:

  • AZURE_CLIENT_ID (from App Registration "Overview" blade)
  • AZURE_CLIENT_SECRET (from App Registration "Certificates & secrets" blade, "Value" field)
  • AZURE_TENANT_ID (from App Registration "Overview" blade)

The values for each of these fields were acquired in the steps above.

Write the code

In a .NET Core application, the following NuGet packages assist you when working with Azure Key Vault.

  • Azure.Security.KeyVault.Secret
  • Azure.Identity

Create a new Console Application in Visual Studio and install the Azure.Security.KeyVault.Secrets and Azure.Identity NuGet packages.

As stated above, we can use the DefaultAzureCredential class to represent the principal used to make calls to our Azure Key Vault and the information (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID) are stored in environment variables.

We create a DefaultAzureCredential object with the following code:

var credentials = new DefaultAzureCredential();

Then, we use this object to create a SecretClient object, as in the code below.

secretClient = new SecretClient(new Uri(keyVaultUri), credentials);

The SecretClient object provides methods to access and manage our Key Vault secrets.

For instance, we can get information about all the secrets in our Key

The following code retrieves information on all secrets in the Key Vault and lists the name, value, and content type of each

Console.WriteLine("All Secrets:");
var allSecrets = secretClient.GetPropertiesOfSecrets();
foreach (var secret in allSecrets)
{
     var secretValue = secretClient.GetSecret(secret.Name);
     Console.WriteLine($"{secret.Name} | {secretValue.Value.Value} | {secretValue.Value.Properties.ContentType}");
}
Console.WriteLine();

Other SecretClient methods allow us to get, set, or delete a Secret, as shown in the following code snippets:

await secretClient.SetSecretAsync(setSecretName, setSecretValue);
var secret = secretClient.GetSecret(setSecretName);
var operation = secretClient.StartDeleteSecret(deleteSecretName);

By default, Azure Key Vault supports soft delete, meaning that a deleted object can be retrieved for a given period after deletion (90 days, by default).
To permanently delete a secret prior to this, we can issue a purge command after the soft delete has completed. We can determine when the soft delete has completed by querying the Boolean DeleteSecretOperation.HasCompleted property.

if (operation.HasCompleted)
{
     secretClient.PurgeDeletedSecret(purgeSecretName);
}

Below is the full code of a .NET Core Console application

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace testKeyVaultConsoleApp
{
     internal class Program
     {
         const string KEYVALUTNAME = "dgtestkeyvault"; // Set this to the name of your key vault
         static string keyVaultUri = $"https://{KEYVALUTNAME}.vault.azure.net";

        static SecretClient secretClient = null;

        static async Task Main(string[] args)
         {
             var credentials = new DefaultAzureCredential();
             secretClient = new SecretClient(new Uri(KEYVAULTURI), credentials);

            ListAllSecrets();

            Console.Write("Input the Secret name to set (ENTER to skip):");
             var setSecretName = Console.ReadLine();
             if (setSecretName != "")
             {
                 Console.Write("Input the Secret value to set:");
                 var setSecretValue = Console.ReadLine();

                Console.WriteLine("Setting secret...");
                 await secretClient.SetSecretAsync(setSecretName, setSecretValue);
                 Console.WriteLine($"Secret {setSecretName} set to {setSecretValue}!");

                // Set content type
                 var secret = secretClient.GetSecret(setSecretName);
                 secret.Value.Properties.ContentType = "Demo Type";
                 secretClient.UpdateSecretProperties(secret.Value.Properties);
             }

            Console.Write("Input a Secret Name to soft delete (ENTER to skip):");
             var deleteSecretName = Console.ReadLine();
             if (deleteSecretName != "")
             {
                 var operation = secretClient.StartDeleteSecret(deleteSecretName);
                 Console.Write($"Deleting secret {deleteSecretName}...");
                 while (!operation.HasCompleted)
                 {
                     Thread.Sleep(1000);
                     Console.Write($".");
                     operation.UpdateStatus();
                 }
                 Console.WriteLine();
                 Console.WriteLine($"Secret {deleteSecretName} deleted!");
             }

            Console.Write("Input a Secret Name to permanently delete (ENTER to skip):");
             var purgeSecretName = Console.ReadLine();
             if (purgeSecretName != "")
             {
                 var operation = secretClient.StartDeleteSecret(purgeSecretName);
                 Console.Write($"Soft deleting secret {purgeSecretName}...");
                 while (!operation.HasCompleted)
                 {
                     Thread.Sleep(1000);
                     Console.Write($".");
                     operation.UpdateStatus();
                 }
                 Console.WriteLine();
                 Console.WriteLine($"Secret {purgeSecretName} deleted!");
                 secretClient.PurgeDeletedSecret(purgeSecretName);
                 Console.WriteLine($"Secret {purgeSecretName} purged!");
             }

            ListAllSecrets();

            Console.WriteLine();
             Console.WriteLine("Done!");
         }

        private static void ListAllSecrets()
         {
             Console.WriteLine("All Secrets:");
             var allSecrets = secretClient.GetPropertiesOfSecrets();
             foreach (var secret in allSecrets)
             {
                 var secretValue = secretClient.GetSecret(secret.Name);
                 Console.WriteLine($"{secret.Name} | {secretValue.Value.Value} | {secretValue.Value.Properties.ContentType}");
             }
             Console.WriteLine();

        }
     }
}

You can find the code here.

NOTE: Visual Studio reads Environment Variables on launch, so it may be necessary to restart Visual Studio after you set the environment variables.

Conclusion

In this article, you learned how to create a Key Vault and manage its secrets from a .NET Console application.