Do you need to encrypt a piece of data in your application? Do you want Azure Key Vault to secure the key? Well, using C# along with a couple of libraries from the Azure SDK, it couldn't be easier to get up and running.
We're going to be using the v4 version of the Azure Security Key Vault Keys client library. We're also going to be needing the Azure Identity client library.
For this intro, I'm going to assume that you have an existing Azure Key Vault. If you haven't got one, here's how to create one.
I'm also going to be authenticating as myself to make the requests to Key Vault purely for demonstration purposes, but in a "real" application you'll almost certainly want to use a managed identity or a service principal. The good news is - the steps/code you'll see below won't change much at all if you opt for either of those alternatives.
For the Key Vault Key operations detailed in this blog to work, the principal under whose identity you're making the requests needs to have an access policy defined, assigned the
Create key management operations, and the
Decrypt cryptographic operation*^. The easiest way to set an access policy is through the Azure Portal, by navigating to your Key Vault, selecting the "Access Policies" tab, and clicking "Add Access Policy". Then, select the above permissions, select the relevant principal, and click "Add". Alternatively, you can use the CLI or PowerShell.
* In most cases, it's quite likely that no single identity will have all 3 of these permissions. Generally, the identity creating the key will be different to that retrieving the key/using the key to perform cryptographic operations. Purely for demonstration purposes, I've assigned these permissions to the same identity (myself).
^ Also, it transpires that the
Get permission seems to incorporate the
Encrypt permission, so when a user has the former permission, the latter doesn't seem to have to be explicitly granted. However, as mentioned above, it could well be that you have multiple identities performing the different operations. Additionally, it's good to be explicit about the permissions you're assigning to identities, rather than relying on implicitly granted permissions.
We're going to create a simple .NET Core 3.1 console application, and taking advantage of the async main method functionality added in C# 7.1 to more realistically imitate asynchronous code that would likely appear in more fully-fledged applications.
That's it - prerequisites and preamble out the way. Let's get going.
Once the .NET Core console app has been created, we should start by adding those package references as project dependencies. So, that's
Azure.Security.KeyVault.Keys, like the following:
Let's add a few variables we're going to need:
Now we have those bits defined, we start by creating a
KeyClient we'll use to interact with the keys in Key Vault:
var keyClient = new KeyClient(new Uri(keyVaultUri), new DefaultAzureCredential());
Naturally, Azure Key Vault will only give out the keys it stores to identities it trusts. From the preamble further up this blog, we should have assigned our identity with the access policies it requires to perform the operations it needs to perform. When we're interacting with Key Vault through the SDK, we need to tell it whom it's interacting with. That's what the second parameter of the
KeyClient constructor does - it's a
TokenCredential, which represents a credential containing a valid AAD token. The
DefaultAzureCredential class derives from the
TokenCredential class, and it tries to retrieve a credential through a number of means:
- EnvironmentCredential - if certain environment variables have been set, authentication with this credential type will be attempted. Used for client-secret flow (service principal), or username-password flow.
- ManagedIdentityCredential - if the deployment environment has been assigned a managed identity, this flow will be attempted.
- SharedTokenCacheCredential - uses tokens in the local cache that's shared between Microsoft apps. This is the method that is being used in this demo - since I'm signed into my AAD account in Visual Studio, everything just works in this scenario.
- InteractiveBrowserCredential - launches the default browser for interactive authentication.
Now we have our client, we can go ahead and create a key (presuming one doesn't already exist):
await client.CreateRsaKeyAsync(new CreateRsaKeyOptions(keyVaultKeyName));
Once created, let's retrieve the same key and assign it to a variable:
KeyVaultKey key = await client.GetKeyAsync(keyVaultKeyName);
Now, to perform the encryption, we actually need a different client - and that's a
CryptographyClient. Typically, the steps to perform the encryption/decryption would happen in a different program to the creation of the Key, but for demonstration purposes, I've included it in the same program here. So, let's go ahead and initialize a cryptography client:
var cryptoClient = new CryptographyClient(key.Id, new DefaultAzureCredential());
To encrypt a string, we first need to encode it as a byte array. We then call
EncryptAsync and specify the encryption algorithm we'd like to use. Finally, we can convert the ciphertext returned in the
EncryptResult to a base 64 encoded string. Here's a method that does all that, given a string as an input:
The output will look something like this:
To decrypt an encrypted string, we need to convert back to a byte array and call
DecryptAsync, and convert the resulting byte array back to a string again, just like the following method:
The result should be exactly what we started with.
Probably the most likely error you'll run into whilst performing any of the above operations is one related to permissions. You might receive an error like this:
Remember that we need four permissions for this code:
which can be set by adding an access policy, as explained further up this blog. And just to reiterate my earlier point - generally these three permissions won't be assigned to the same identity - rather, separate identities performing the separate operations would get the permissions they need - and only the permissions they need.
Anyway, that's it - a round-trip of encryption and decryption of a string using a key managed by Azure Key Vault.
Here's the full code:
Hope you've found this useful!