I was able to spend a little time recently with a new Azure service, the Key Vault service, for some work I was doing. It’s a pretty valuable and not too difficult service that solves an age old problem – where can I securely keep secrets for my applications in Windows Azure. Actually because of the way it’s implanted you really don’t even need to have your application hosted in Azure…but I’m getting a little ahead of myself. Let’s start with the basics. As a precursor to what I have here, I’ll just point out that there’s actually some pretty good documentation on this service available at http://azure.microsoft.com/en-us/services/key-vault/.
Before you start trying to build anything, you really need to have the latest version of the Azure PowerShell cmdlets, as well as the new cmdlets they’ve built for working with Key Vault. You can get the very latest of the Azure PowerShell cmdlets by going here: https://github.com/Azure/azure-powershell/releases. You can get the Key Vault cmdlets by going here: https://gallery.technet.microsoft.com/scriptcenter/Azure-Key-Vault-Powershell-1349b091.
Create a New Vault and Secret(s)
The next step is to crack open your Azure PowerShell window and load up the Key Vault cmdlets. You can do that like this:
Set-ExecutionPolicy Bypass -Scope Process
I’m just turning off policy to only run signed cmdlets with the first line of code (and just in this process), and then loading up the cmdlets with the next line of code. After that you need to connect to your Azure AD tenant like this:
If you have multiple subscriptions and you want to target the specific subscription where you want to create your Key Vault and secrets and keys, then you can do this:
Set-AzureSubscription -SubscriptionId some-guid-here
You’ll see a list of guids for your subscription after you log in with the add-azureaccount cmdlet. Now that you’re logged in and set in your subscription, you can do the first step, which is to create a new vault. The PowerShell for it is pretty easy – just this one line of code:
New-AzureKeyVault -VaultName “SteveDemo” -ResourceGroupName “SteveResources” -Location “West US”
There are a few things worth noting here:
- The VaultName must be unique amongst ALL vaults in Azure. It’s just a like an Azure storage account in that sense. The name will become part of the unique Url you use to address it later.
- The ResourceGroupName can be whatever you want. If it doesn’t exist, the cmdlets will create it.
- The locations are limited right now. In the US you can create a vault in the West and East but not Central. Azure should have some documentation somewhere on which locations you can use (i.e. I’m sure they do, I just haven’t gone looking for it yet).
Okay cool – we got a vault created, now we can create keys and secrets. In this case I’m going to use the scenario where I need some kind of database connection string. Assume as well that like in most cases, I have a separate database for dev and production. So what I’m going to do is just create two secrets, one for each. Here’s what that looks like:
$conStrKey = ConvertTo-SecureString ‘myDevConStr’ -AsPlainText -Force
$devSecret = Set-AzureKeyVaultSecret -VaultName ‘SteveDemo’ -Name ‘DevConStr’ -SecretValue $ conStrKey
$ conStrKey = ConvertTo-SecureString ‘myProdConStr’ -AsPlainText -Force
$prodSecret = Set-AzureKeyVaultSecret -VaultName ‘SteveDemo’ -Name ‘ProdConStr’ -SecretValue $ conStrKey
Awesome, we’re ready to go, right? Mmm, almost, but not quite. Like all things Azure, you need to configure an application that you’ll use to access these secrets. But actually its different (of course) than other apps, in that you don’t pick it from a list of services and select the features you want to use. That may come later, but it’s not here yet.
Grant Your Application Rights to the Secrets
There are a few steps here to get your app rights to the secrets you created.
- Create a new application in Azure AD. I won’t go through all the steps here because they’re documented all over the place. But the net is you create a new app, say it’s one you are developing, and type in whatever value you want for the sign in and app ID. After that you need to go copy the client ID and save it somewhere, then create a new key and save it somewhere. You’ll use these later.
- Go back to your PowerShell window and grant rights to read keys and/or secrets to your application. You can do that with a line of PowerShell that looks like this:
Set-AzureKeyVaultAccessPolicy -VaultName ‘SteveDemo’ -ServicePrincipalName theClientIdOfYourAzureApp -PermissionsToKeys all -PermissionsToSecrets all
In this case I kind of cheated and took the easy way out by granting rights to all possible permissions to my app. If you just wanted it to be able to read secrets then you could configure it that way. One other thing worth noting – one of the most common errors I have seen from folks using this service is that they only remember to grant PermissionsToKeys or PermissionsToSecrets but not both. If you do that then you will get these kind of weird errors that are say something like “operation ‘foo’ is not allowed”. Well, yeah, technically that’s correct. What’s really happening is that you’re forbidden from doing something that you have not expressly granted your application rights to do. So be on the lookout for that.
Use Your Secrets
Okay cool, now that we’ve got our app all set up we can start using these secrets, right? Yes! :-) The first thing I would recommend doing is downloading the sample application that shows off performing all of the major Key Vault functions. The latest sample is at http://www.microsoft.com/en-us/download/details.aspx?id=45343. I just know they will change the location any day now and my blog will be out of date, but hey, that’s what it is today. Now there is supposed to be a Nuget package that would allow you to use this more easily from .NET managed code, but I currently cannot find it. If you go get the code download though you will see a sample project that you can easily compile for a nice assembly-based access to the vault.
Going back to something I mentioned at the beginning though – about not “even need(ing) to have your application hosted in Azure” – one of the really great things about this service is that it’s all accessible via REST. So…that gives you LOTS of options, both for working with the content in the vault, as well as the tools, platforms, and hosting options for your applications that use it. For me, I feel that the most common use case by a wide, wide margin is an application that needs to read a secret – like a connection string. So what I did was go through the sample code and reverse engineer out a few things. The result was a much smaller, simpler piece that I use just for retrieving a secret. The pseudo-code goes something like this:
- Get an Azure AD access token
- Use the client ID and client secret you obtained earlier, and combine that with the Azure AD resource ID for the Key Vault service – which is https://vault.azure.net.
- Get the access token by creating a ClientCredential (with the client ID and client secret), and using the resource ID. The code looks something like this:
var clientCredential = new ClientCredential(client_id, client_secret);
var context = new AuthenticationContext(Authority + authorityContext, null);
var result = context.AcquireToken(“https://vault.azure.net”, clientCredential);
There’s one other REALLY important thing to note here. For those of you familiar with Azure AD and AuthenticationResults, you may be used to getting your them using the Common Login authority. In this case, you will get an AuthenticationResult, but you will get a 403 Forbidden when trying to use it. Mucho painful debugging to figure this out. You MUST use the tenant ID of the Azure AD instance where your application is registered. The tenant ID is just another GUID you can get out of the Azure portal. So for instance in the code above where it’s getting the AuthenticationContext, those two variables look like this:
const string Authority = “https://login.windows.net/”;
string authorityContext = “cc64c719-d217-4c44-dd24-42c18f9cb9f2”;
- Create a new HttpClient and plug in the access token from step 1 into an authorization header. That code looks something like this:
HttpClient hc = new HttpClient();
hc.DefaultRequestHeaders.Authorization = new
- Configure the request headers to indicate that you accept application/json, like this:
- Create the Url you are going to use to access your secret. Here’s my example:
A couple of key things to remember about this Url:
- “stevedemo” is the name of my vault. This is why it has to be unique in all of Azure.
- “prodconstr” is the name of the secret I created. There is also an ability to add a GUID after that which corresponds to a specific version of a secret if needed. I won’t cover it here, but it’s in the documentation if you need it.
- Request your secret. My code looks like this:
//NOTE: Using await here without ConfigureAwait causes the
//thing to disappear into the ether
HttpResponseMessage hrm = await hc.GetAsync(new
- Get the results. My code:
Secret data = await DeserializeAsync<Secret>(hrm);
result = data.Value;
In the spirit of being honest… :-) …I borrowed the code to deserialize the results into a class. It’s extremely short and the class is quite simple, so it only takes about 30 seconds of copy and paste.
Using the Secret
So there you have it – a pretty quick and easy way to get at your secrets. Using it within my code then is really simple. I have one line of code to retrieve the secret using the code shown above:
conStr = VaultSecret.GetSecret(KEY_VAULT_NAME, KEY_VAULT_SECRET_NAME).Result;
Where VaultSecret is the name of my class where I put the code I showed above, GetSecret is the method I created that contains that code, and, well, hopefully the two parameters are self-explanatory. Overall – good stuff, all things being equal relatively quick to get up and going with it.