Some fun with Azure Key Vault REST API and HttpClient – Part 2

In previous article, I demonstrated how to use HttpClient to work with Azure Key Vault REST API. With this approach, you shouldn’t worry about your programming language skills. What I meant was that you could even use Python, for instance, to make a HttpClient object and call Azure Key Vault REST API. This approach gives developers more flexibility to work with Microsoft Azure as it does not limit to the platform supportability.

You were learnt by getting started with creating a new key vault which is used to protect your key, secret or certificate. In this article, let’s take some time looking into secret in Azure Key Vault.

Keep track of the series:

Before we move on, I’d like to suggest the following references so you can get to the whole things around Azure Key Vault:

In Azure Key Vault, secret is a sequence of bytes limited maximum to 25K bytes each. Secret can be value and even a certificate you want to protect. Secret is commonly used to store sensitive configuration such as database connection string, password or a verification key. For the use of secret, Azure Key Vault adds an additional protection layer for such a sensitive information.

This article does the following things:

  • Check if the secret you are going to create exists under the vault.
  • Create a new secret

Environment variable and configuration management

In the app.config  file, add one more entry to declare your secret name.

For demonstration purpose, I’d like to store my storage account access key to Azure Key Vault as a secret. My application before invoking some Azure Blob storage function, it needs to retrieve storage access key from Azure Key Vault first. From the app.config, the secret will be created into the given vault name (the one you created previously).

Always remember to install Microsoft.WindowsAzure.ConfigurationManager Nuget package

And also declare variables in program.cs

Building AuthHelper class to get access token

Follow the previous article to re-use the AuthHelp class which executes POST method to the Azure AD authorization endpoint in order to get access token. The only difference you need to change is resource. Previously we targeted to Azure Resource Management endpoint to create an Azure Key Vault resource in your Azure subscription. Hence, you set the resource as follows:

However, the resource we are going to request access is not Azure Resource Management endpoint anymore. It needs to be explicitly Azure Key Vault endpoint, which is as follows:

Make sure the variable has no forward slash “/“. With the slash, you will get 401 access denied message when making a request to the resource endpoint.

Build your base HttpClient object 

Before you can make a request to Azure Key Vault resource, let’s create a HttpClient object which contains authorization header including access token.

Note that the base URI (Uniform Resource Identifier) is not the same as previous article. It is your vault identifier. Also remember to define  SetSecret()  method which we will build at the last section. In the Main()  method, we also call MainAsync()  which invokes SetSecret()  method.

Getting all secrets under the vault

To safely create a new secret which exists under the given vault, we should get all secrets first. If the named secret already exists, Azure Key Vault allows you to create a new version of that secret. For the demonstration purpose, we are not going to create a new version of the existing secret. Instead, we will create a fresh secret.

First, make sure your service principal has Get secret permission which you defined in the request body lastly.

To get list of existing secrets, let’s use Task<List<string>>  in asynchronous. First, we need to declare the Url which is included in the GET request. The full URL needs to be in the following structure:

Like previous example, we also need to load a JObject from response body which contains information related to the vault in JSON format. Pay attention to the response body, you will realize that this is an Array which contains all existing secrets.

What we really need is to query all id  element in the response body. Here we can initialize a List<string>  and use SelectTokens() with LINQ to extract value of each ID element. It took me several hours to find the comfortable approach to quickly extract value.

Another approach is to initialize a new IList<JToken>  and access to nested property using bracket like [“value”][“id”] like this example. However, with list of string values, we would easily do If statement to compare return string.

Here is the full code snippet of get all existing secrets under the given vault

Creating a new secret

Right here, since we get all existing secrets, we can make a decision to not create a new version of any existing one. Instead, we create a new secret. The following If statement can be done easily to verify. The statement returns boolean after checking if the list of existing secrets contains the given secret identifier/

In fact, there could be another way to get all the secrets using ForEach() . See the below example:

Instead of comparing the secret identifier, this code uses ForEach loop in the JObject. Does it work? Yes, the code works completely, except one thing which is Async method. Because we use Async, the loop works asynchronously. This basically means there can be two parallel threads running to check the statement. And of course the code doesn’t throw an exception because Azure allows you to overwrite to an existing secret with a new version created. The number of versions depends on the number of existing secrets. As a result, you could have not only one version created in the given secret.

Next, prepare the request body to use with PUT method

For demonstration purpose, I copied the storage account access key, it can also be a database connection string or any configuration you don’t want to store in app.config file. In the attributes  body, declare secret metadata

  • nbf: the abbreviation of Not Before. This is the activation date of the secret.
  • exp: the abbreviation op Expiration. This is the expiration date of the secret
  • enabled: boolean type to enable/disable the secret

Both nbf and exp value must be Integer in UTC format. I cann’t seem to find an easy approach to convert DateTime to Int type. Searching over the Internet, folks recommend to use DateTime.Ticks  to return Int64 type but when implementing this method, I always get 400 Bad Request saying the attributes is in valid format. Convert.ToInt32()  also returns InvalidCastException. IMO the fastest way is to use online conversion tool such as https://www.unixtimestamp.com or https://www.epochconverter.com. For example, in my nbf value, 1519084800 is as known as Tuesday, February 20, 2018 12:00:00 AM (GMT)

Execute the code and load the JSON value containing your new secret.

Conclusion

There are a few lessons learnt in this article. First, Azure Key Vault REST API fully supports to retrieve existing secrets. The response body contains all secret identifiers under the given vault. Azure Key Vault also allows you to manage secret version. It does not prevent from creating a new secret when being existed. Through the example, you also get some points about response body in JSON format and how to extract nested elements. Finally, you have made the request body of a secret before making a PUT request to Set Secret API endpoint.

Sample code is accessible from here. If you have a better approach, or can review my code, I’d be very happy to learn from and discuss with you.

Comments

  1. Liu Jo
    February 21, 2018 — 2:29 am

    Very comprehensive and explanation in detail about Key Vault REST API which Microsoft does not give much.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2018 The Soldier of Fortune.