Managing keys in Azure key vault using .NET code

Managing keys in Azure key vault using .NET code

In past few articles, I have tried to explain how key vaults can be created and can be accessed from .NET core web application.

In the posts, where I have explained how to use service principal to access key vault, I registered application in Azure AD.

In this article, let’s see how can we create service principal using Azure CLI and use it to access the key vault.

Plan of Action

We are going to create a console application that performs create, update, delete, purge operations on key vault. This console application will use the service principal, which will be created using Azure CLI.

So, below are the steps which we are going to perform:

  • Create key vault
  • Create service principal using CLI
  • Add access policy in key vault
  • C# Code to perform create, update, delete, purge operations

I have created Azure CLI script for first three operations. So there will be a section to cover it. The C# code is covered in the subsequent section of this article.

So, let’s get started !

Azure CLI Script

Below is the Azure CLI script to create the key vault and create the service principal. Then the script also configures the access policy on key vault and provides all the access rights to the service principal.

## Create Azure Key Vault
## Resource group name and key vault name should be updated
az keyvault create –resource-group MyResourceGroup –name MyKeyVault
## Create service principal
## Application name is just a display name so it cannot be
az ad sp create-for-rbac -n app-name –skip-assignment
## Output of above command is in below format:
## {
## "appId": "GUID-app-ID",
## "displayName": "app-name",
## "name": "http://app-name",
## "password": "some-password",
## "tenant": "GUID-tenant-ID"
## }
##
## Copy AppId (i.e. Azure Client ID), Tenant Id and password
## It is required in the console application
## Command to add access policy in key vault
## Take client id from above output and use it in below command
## This command provides all permissions to the service principal
az keyvault set-policy –name MyKeyVault –spn <<GUID-app-ID>> –key-permissions backup delete get list create encrypt decrypt update restore recover purge
view raw keyvault.sh hosted with ❤ by GitHub

If you want to use Azure Portal for preforming above steps, refer my blog posts mentioned below:

Note for curious minds…

The az ad sp create-for-rbac command ultimately creates the app registration in the Azure AD.

If you go to App registrations -> All applications tab from the Azure AD, it would show the application with app-name (which we have provided in the command).

Console App

Create a .NET Core console application using Visual Studio 2019.

NuGet Packages

Then add reference to below NuGet packages:

Concepts

There are three important classes which we are going to use:

  • KeyClient – provides both synchronous and async APIs, that can be used to interact with key vault
  • Cryptography Client – provides both synchronous and async APIs, to perform cryptographic operations with keys stored in Key Vault.
  • KeyVaultKey – represents keys from the key vault, representing the value of key and some other properties
  • ClientSecretCredential – is the class from Azure.Identity package which takes tenant id, client id and client secret of the service principal which is helped for app authentication.

Code

Below is the sample code which shows some basic operations performed on keys stored in key vault.

The sample snippet also tries to use the keys in key vault and shows how they can be used for encryption and decryption using Cryptography client.

using System;
using System.Text;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Keys;
using Azure.Security.KeyVault.Keys.Cryptography;
namespace KeyVaultManager
{
class Program
{
//// replace your key vault name
static string keyVaultUrl = "https://<<your-key-vault>&gt;.vault.azure.net";
//// Client ID from the output of service pricipal creation output
static string clientId = "{GUID_ClientID}";
//// Tenant ID from the output of service pricipal creation output
static string tenantId = "{GUID_TenantID}";
//// Password from the output of service pricipal creation output
static string clientSecret = "{Client_Secret}";
static async Task Main(string[] args)
{
var client = new KeyClient(vaultUri: new Uri(keyVaultUrl), credential: new ClientSecretCredential(tenantId, clientId, clientSecret));
// Create a software RSA key
var rsaCreateKey = new CreateRsaKeyOptions("rsa-key-name", hardwareProtected: false);
KeyVaultKey rsaKey = await client.CreateRsaKeyAsync(rsaCreateKey);
Console.WriteLine("Created the key….");
Console.WriteLine($"rsaKey.Name: {rsaKey.Name}");
Console.WriteLine($"rsaKey.KeyType: {rsaKey.KeyType}");
Console.WriteLine("==================================================");
Console.WriteLine();
// Retrieve
KeyVaultKey key = await client.GetKeyAsync("rsa-key-name");
Console.WriteLine("Retrieve the key");
Console.WriteLine($"key.Name: {key.Name}");
Console.WriteLine($"key.KeyType: {key.KeyType}");
Console.WriteLine("==================================================");
Console.WriteLine();
// Update
KeyVaultKey updateKey = await client.CreateKeyAsync("rsa-key-name", KeyType.Rsa);
// You can specify additional application-specific metadata in the form of tags.
updateKey.Properties.Tags["foo"] = "updated tag";
KeyVaultKey updatedKey = await client.UpdateKeyPropertiesAsync(updateKey.Properties);
Console.WriteLine("Update Initiated.");
Console.WriteLine($"updatedKey.Name: {updatedKey.Name}");
Console.WriteLine($"updatedKey.Properties.Version: {updatedKey.Properties.Version}");
Console.WriteLine($"updatedKey.Properties.UpdatedOn: {updatedKey.Properties.UpdatedOn}");
Console.WriteLine("==================================================");
Console.WriteLine();
/// Delete
DeleteKeyOperation operation = await client.StartDeleteKeyAsync("rsa-key-name");
DeletedKey deletedKey = operation.Value;
Console.WriteLine("Delete operation initialted.");
Console.WriteLine($"deletedKey.Name: {deletedKey.Name}");
Console.WriteLine($"deletedKey.DeletedOn: {deletedKey.DeletedOn}");
Console.WriteLine("==================================================");
Console.WriteLine();
// Wait for deletion to complete
await operation.WaitForCompletionAsync();
// Recover deleted key
var recoverOperation = await client.StartRecoverDeletedKeyAsync("rsa-key-name");
await recoverOperation.WaitForCompletionAsync();
Console.WriteLine("Recovery completed");
Console.WriteLine("==================================================");
Console.WriteLine();
// Create crypto client and demo of encryption / decryption
var cryptoClient = new CryptographyClient(keyId: key.Id, credential: new ClientSecretCredential(tenantId, clientId, clientSecret));
byte[] plaintext = Encoding.UTF8.GetBytes("If you can dream it, you can do it.");
// encrypt the data using the algorithm RSAOAEP
EncryptResult encryptResult = await cryptoClient.EncryptAsync(EncryptionAlgorithm.RsaOaep, plaintext);
Console.WriteLine("Encryption demo.");
Console.WriteLine("Encrypted Base64: " + Convert.ToBase64String(encryptResult.Ciphertext));
Console.WriteLine("==================================================");
Console.WriteLine();
// decrypt the encrypted data.
DecryptResult decryptResult = await cryptoClient.DecryptAsync(EncryptionAlgorithm.RsaOaep, encryptResult.Ciphertext);
Console.WriteLine("Decryption demo.");
Console.WriteLine("Decrypted: " + Encoding.UTF8.GetString(decryptResult.Plaintext));
Console.WriteLine("==================================================");
Console.WriteLine();
// Purge
DeleteKeyOperation deleteOperation = await client.StartDeleteKeyAsync("rsa-key-name");
await deleteOperation.WaitForCompletionAsync();
DeletedKey purgekey = deleteOperation.Value;
await client.PurgeDeletedKeyAsync(purgekey.Name);
Console.WriteLine("Purge Initiated.");
Console.WriteLine($"purgekey.Name: {purgekey.Name}");
Console.WriteLine("==================================================");
Console.WriteLine();
}
}
}
view raw Program.cs hosted with ❤ by GitHub

If you run the console application, you would be able to view the keys in key vault (if they are not deleted / purged yet).

Conclusion

We have seen how to manage keys in key vault. Also, there are nuget packages available for certificates and secrets, thus similar code can easily be written for managing certificates and secrets too.

I hope you enjoyed this article. Let me know your thoughts.

Leave a Reply