Using Azure Key Vault to manage your secrets
Tags: azure, javascript, tutorial, webdev
Published: 2021-01-13 18:15:03

---
title: Using Azure Key Vault to manage your secrets
published: true
description: Azure Key Vault service is the recommended way to manage your secrets regardless of platform (e.g Node.js, .NET, Python etc). This article takes you through why Key Vault and how to work with it in local development as well as when your app is deployed on Azure.
tags: azure, javascript, tutorial, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/bpsi8poexuej51yjbvbk.jpg
---
 
TLDR; this article tells you why you should use Azure KeyVault to store and manage your secrets. Furthermore it takes you all the way from local development to deployed on Azure (there are some differences in how to authenticate).

Azure Key Vault service is a service on Azure. It's a vault for your secrets that is encrypted. It solves the following problems:

- **Secrets Management** - Azure Key Vault can be used to Securely store and tightly control access to tokens, passwords, certificates, API keys, and other secrets.
- **Key Management** - Azure Key Vault can also be used as a Key Management solution. Azure Key Vault makes it easy to create and control the encryption keys used to encrypt your data.
- **Certificate Management** - Azure Key Vault is also a service that lets you easily provision, manage, and deploy public and private Transport Layer Security/Secure Sockets Layer (TLS/SSL) certificates for use with Azure and your internal connected resources.

## Why use it

Key Vault greatly reduces the chances that secrets may be accidentally leaked. There's also some additional benefits such as:

- **Secrets are separate from code** Application developers no longer need to store security information in their application.

- **Access via URIs**. Your applications can securely access the information they need by using URIs. These URIs allow the applications to retrieve specific versions of a secret.

- **No need for custom code**. There is no need to write custom code to protect any of the secret information stored in Key Vault.

- **Monitoring**, you can enable logging for your Vaults. You can configure the monitoring to:
   - Archive to a storage account.
   - Stream to an event hub.
   - Send the logs to Azure Monitor logs

- **Authentication via AAD, Azure active directory**. Access to a Key Vault requires proper authentication and authorization. Authentication is done via Azure Active Directory.

- **Two ways to authorize**. Authorization may be done via Azure role-based access control (Azure RBAC) or Key Vault access policy

## References

- [Learn module Azure Key Vault](https://docs.microsoft.com/en-us/learn/modules/manage-secrets-with-azure-key-vault?WT.mc_id=academic-12792-chnoring). If you are completely new to Key Vault this is the best place to start. It takes you through explaining what Key Vault is, what to use it for. How to run something locally and how to deploy it to the cloud.

- [More on auth](https://docs.microsoft.com/en-us/azure/key-vault/general/overview#securely-store-secrets-and-keys?WT.mc_id=academic-12792-chnoring)

- [Quickstart Node.js](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-node?WT.mc_id=academic-12792-chnoring) This is a quickstart that tells you how to work with secrets locally using Node.js. Great no-nonsense guide if you want to get started quickly.

- [Quickstart .NET](https://docs.microsoft.com/en-us/previous-versions/azure/key-vault/quick-create-net-v3?WT.mc_id=academic-12792-chnoring) A good quick start article showing how to create a Key Vault, use the .NET SDK and a service principal to authenticate.

- [KeyVault secrets](https://docs.microsoft.com/en-us/azure/key-vault/secrets/about-secrets?WT.mc_id=academic-12792-chnoring). Good page that gives more of an understanding of how secrets are stored and what different permission levels exist among other things.

## Authenticating to Key Vault

An important thing to realize when you want to read from the Key Vault within an app is that you need two different approaches depending on whether you are developing locally, or you have deployed the app to Azure. Why is that? 

Let's explain the two different situations:

- **In development locally**, you can be authenticated by using either Azure CLI and the `az login` command. You can also use the Azure extension for VS Code and log in to Azure that way. What happens when you use either of those methods a credential is created on your machine. If you then use the official SDKs for your chosen platform, it will be able to authenticate using said credential.

- **When deployed on Azure**. To reiterate, your code will most likely use an SDK for a supported language platform like .NET, Node.js, Python etc. Now, the SDK works for you in both when developing locally and deployed to Azure. It looks for credentials in many places like Az CLI and Visual Studio Code as we've already mentioned. However, once deployed, your app has access to neither of those two, so what does it do? It uses either environment variables (in App Settings for example) or it uses a so called _managed identity_ to authenticate.

   A managed identity is an _impersonated_ identity you can create, either based on your service (a web app for example) or based on your user. What you do is to run a command, with either your user or your app as an argument, and back comes an identity and a secret. Here's an example of how you can create such an identity:

   ```bash
   az webapp identity assign \
    --resource-group "<resource group name>" \
    --name "<your-unique-app-name>"
   ```

   The above command returns a principal id that you will use as an argument in the next command. Once you have that identity created you need to assign it to the Key Vault using `az keyvault set policy`:

   ```bash
   az keyvault set-policy \
    --secret-permissions get list \
    --name "<your-unique-vault-name>" \
    --object-id "<your-managed-identity-principalid>"
   ```

   After that, you are ready to deploy your app to Azure and Azure Active Directory will authenticate your app and let you read from the Key Vault. This will all be shown in detail further down in the article, but now you know roughly what goes on.

### Permissions

The `set-policy` command above not only associates your identity to the Key Vault, it also sets permissions. The argument `--secret-permissions` contains a list of permissions that determines if you are able to read, write and manage secrets. Be as restrictive as you can who can do what with your Key Vault.  In general, I reason like this when it comes to permissions:

- **Read, for most apps**. Most apps only need to read a secret.
- **Write, only when absolutely needed**. Apps or users that needs this access is some kind of admin. Either the app manages secrets via a web API for example or there's an admin user that some other way needs to do something advanced to the secrets.

### Have a safe behavior

Even though Key Vault helps you keep your secrets secure, it can still leak if you're not careful. You don't want to ever show the value of a secret on a web page or as part of an error. What you can do, is to have a safe behavior and ensure you do things such as:

- **Be restrictive with permissions**, if your app only needs to read a secret, don't give it permission to SET, DELETE or do something else.
- **Rotate keys**, you can change the values of the keys/secrets. The apps using those keys won't be affected as they only operate on they keys name, not its value.

## DEMO, create a Key Vault store and read a secret

Next, you will be taken through a series of steps where you will get to do the following:

- **Create a KeyVault**, you will create a Key Vault from the command line using Azure CLI
- **You will add secrets**, to the Key Vault and ensure you can read back the value using Node.js and some SDK libraries.
- **Create an assign identity**, you will then create a managed identity, using your web app as an argument and assign to the Key Vault
- **Deploy app**, once you have all these parts in place, you will deploy the app and see that it can still read secrets from the Key Vault.

To create a Key Vault, follow these steps:

1. **Login to Azure.** In a terminal type `az login`:

   ```bash
   az login
   ```

   Select the user you want to login with.

2. **Create a resource group.** You may use an existing resource group at this point, but if you want to create a new one, type the following:

   ```bash
   az group create --name "<a name for resource group>" -l "EastUS"
   ```

3. **Create the Key Vault**. Run the `az keyvault` command below:

   ```bash
   az keyvault create --name "<unique vault name>" --resource-group "keyvaultrg" --location "EastUS"
   ```

4. **Create a secret**, using the following command `az keyvault secret set`:

   ```bash
   az keyvault secret set --vault-name "<unique vault name>" --name "mySecret" --value "abc123"
   ```

5. **Read the secret**, from the vault by running this command `az keyvault secret show`:

   ```bash
   az keyvault secret show --vault-name="<unique vault name>" --name="mySecret"
   ```

## DEMO, Reading a secret from your code, when developing

There's SDKs for most major platforms. I'll be selecting the Node.js one for this demo. If you want the C# one you can select this language pivot:

> [C# KeyVault SDK](https://docs.microsoft.com/en-us/learn/modules/manage-secrets-with-azure-key-vault/5-access-secrets-from-web-app?pivots=csharp)

1. Run the command `az login` to ensure you are logged into Azure before proceeding. This will place a credential on your machine that the SDK will be able to pick up.

   ```bash
   az login
   ```

   Select the Azure user that you want and then close the browser windows when asked.

2. Create a file _app.js_
3. Instantiate a Node.js project by running the `npm init` command like so:

   ```javascript
   npm init -y
   ```

4. Download the needed SDK libraries from npm using the `npm install` command like so:

   ```javascript
   npm install @azure/identity @azure/keyvault-secrets dotenv
   ```

   `dotenv` is not part of the SDK, it just let's us define some environment variables in a _.env_ file and they get read to the env variables at initialization.

5. **Add imports**. Open _app.js_ and add the following two lines at the top:

   ```javascript
   require('dotenv').config()

   const { DefaultAzureCredential } = require("@azure/identity");
   const { SecretClient } = require("@azure/keyvault-secrets");
   ```

   The first line ensures values from the _.env_ file is read in. Given the upcoming code the content of _.env_ file should look something like this:

   ```output
   VAULT_NAME=<key vault value, change me>
   ```

6. **Instantiate a client**. We do that with the following lines of code:

   ```javascript
   const secretName = "mySecret";
   const keyVaultName = process.env["VAULT_NAME"];
   const KVUri = "https://" + keyVaultName + ".vault.azure.net";

   const credential = new DefaultAzureCredential();
   const client = new SecretClient(KVUri, credential);
   ```

   Note how the first two lines help construct the URL to the Key Vault given it's name, that it reads from `VAULT_NAME` variable from our _.env_ file. Next an instantiation of `DefaultAzureCredential` is done. This instance will find the credential produced by `az login`.

   > NOTE, we will need to change how this authentication happens once we deploy the app, but this works for now.

7. **Retrieve secrets value**. Lastly, we add code retrieve the value of the secret:

   ```javascript
   async function main() {
    const retrievedSecret = await 
    client.getSecret(secretName);
    console.log(retrievedSecret);
   }

   main();
   ```

8. **Add npm "start" command**. Add an entry to _package.json_ and the script section:

   ```json
   "start": "node app.js"
   ```

9. **Run the app**, by typing the following in the console:

   ```bash
   npm start
   ```

   This should give you a response looking something like this:

   ```javascript
   {
     value: 'abc123',
     name: 'mySecret',
     properties: {
       expiresOn: undefined,
       createdOn: 2021-01-11T18:06:19.000Z,
       updatedOn: 2021-01-11T18:06:19.000Z,
       value: 'abc123',
       id: 'https://<key vault name>.vault.azure.net/secrets/mySecret/<the secret>',
      tags: { 'file-encoding': 'utf-8' },
      vaultUrl: 'https://<key vault name>.vault.azure.net',
      name: 'mySecret',
      version: '<version>',
      enabled: true,
      recoverableDays: 90,
      recoveryLevel: 'Recoverable+Purgeable'
   }
   ```

   You can see that you are able to successfully retrieve the value of your secret from the Key Vault and via code. Great, congrats.

## DEMO, reading a secret from code, when deployed

As we are looking to deploy our app next, there are two things we need to do:

- **Rebuild to an API**. Ensure we rebuild the app to a web API, we will use Express framework for this
- **Authenticate via a principal**. We will need to perform the following steps for that:
   1. Create a webapp on Azure.
   1. Create a principal, using the name of the app as an arg.
   1. Associate the principal to the Key Vault.
- **Deploy the app**. That's something we can do via the command line.

### Rebuild to an API

First, we will need to rebuild the app to Express. We do this just so we can interact with the app once deployed. We will display the value of the secret.

> Don't do this in a real scenario, this is just to show that we have the proper access to the Key Vault.

1. **Install web framework**. Install express using `npm install`

   ```bash
   npm install express
   ```

2. **Add route**. Ensure you have _app.js_ open and change the code to the following:

   ```javascript
   // this is not needed when deployed
   // require('dotenv').config()

   const { DefaultAzureCredential } = require("@azure/identity");
   const { SecretClient } = require("@azure/keyvault-secrets");
    
   const app = require('express')();
   const port = process.env.PORT || 3000;
    
   const keyVaultName = process.env["VAULT_NAME"];
   const KVUri = "https://" + keyVaultName + ".vault.azure.net";
    
   const credential = new DefaultAzureCredential();
   const client = new SecretClient(KVUri, credential);
    
   const secretName = "mySecret";
    
   app.get('/api/test', async(req, res) => {
      const secret = await getSecret();
      
      res.type('text');
      res.send(secret);
   });
    
   async function getSecret() {
      const retrievedSecret = await client.getSecret(secretName);
      return retrievedSecret;
   }
    
   app.listen(port, () => {
      console.log('server running');
   })
   ```

 What we have now is an express app with a route to `/api/test`.

1. **Test your program**, by running `npm start` in the console. In the browser, navigate to `http://localhost:3000/api/test`. It should show your secret as a JSON response.

### Create the web app

Because we plan to deploy this on Azure we need to make sure our app properly authenticates to Azure AD and that the Key Vault is ok with us reading from it. There's just a few steps to make that happen:

1. **Create a service plan**, first need a service plan. Run the command `az appservice plan create`, like so:

   ```bash
   az appservice plan create \
    --name "<unique service plan name for your subscription>" \
    --sku FREE \
    --location centralus \
    --resource-group "<existing resource group>"
   ```

2. **Create a web app**, we need to create web app first as we will use it's name as an argument when we create a so called principal. Run `az webapp create`:

   ```bash
   az webapp create \
    --plan "<unique service plan name for your subscription>" \
    --runtime "node|10.6" \
    --resource-group "<existing resource group>" \
    --name "<unique app name>"
   ```

3. **Create the app settings**, next configure the app setting on the web app by calling `az webapp config appsettings set`:

   ```bash
   az webapp config appsettings set \
    --resource-group "<existing resource group>" \
    --name "<unique app name>" \
    --settings 'VAULT_NAME=<your-unique-vault-name>' 'SCM_DO_BUILD_DURING_DEPLOYMENT=true'
   ```

   The command above will ensure that `process.env['VAULT_NAME']` will get populated once deployed. Also we no longer need the `dotenv` lib to read from the _.env_ file.

### Authenticate via a principal

There are two things that needs doing. Creating the impersonated identity and assigning the identity to the Key Vault, and in doing so give the needed permissions to be able to read the secrets values.

1. **Create a service principal**, run the command `az webapp identity assign`:

   ```bash
   az webapp identity assign \
    --resource-group "<existing resource group>" \
    --name "<unique app name>"
   ```

   This will produce a JSON response that contains a field **principalId**. You will use that in the next command to associate an identity with a Key Vault, while adding a set of permissions.

2. **Grant permission to the Key Vault**, run the command `az keyvault set-policy`:

   ```bash
   az keyvault set-policy \
    --secret-permissions get list \
    --name "<your-unique-vault-name>" \
    --object-id "<principalId>"
   ```

   Here we can see how we assign `get` and `list` as permissions for our identity, when it gets associated to the Key Vault. That's what's needed for the app to be able to read from the Key Vault.

   > We would have needed another set of permissions if we wanted to create or delete a secret for example.

### Deploy the app

To deploy the app, there's only one command we need to run. All that's needed is to compress the application and deploy it. 

- **Deploy the app**. As a final step, deploy the app using the command:

   ```bash
   zip site.zip * -x node_modules/

   az webapp deployment source config-zip \
    --src site.zip \
    --resource-group "<existing resource group>" \
    --name "<unique app name>"
   ```

   The above command will pack up all your files, _node_modules_ excluded, into a file _site.zip_. Then the files are deployed. A few minutes later you will app your app up and running and your Key Vault showing the value of your secret **mySecret** if you navigate to **deployedUrl/api/test**

## Summary

This article was somewhat long, but it did tell you why you should use the Azure Key Vault service. It also told you how to work with the Key Vault in local development and finally how you needed to change your source code and thereby prepare it for deployment. I hope it was helpful.