Protect your function app with Azure KeyVault

My - Sep 26 '19 - - Dev Community

This article is part of #ServerlessSeptember. You'll find other helpful articles, detailed tutorials, and videos in this all-things-Serverless content collection. New articles are published every day — that's right, every day — from community members and cloud advocates in the month of September.

Find out more about how Microsoft Azure enables your Serverless functions at https://docs.microsoft.com/azure/azure-functions/.

You should never store secrets in code. But what if your function need access to a secret, ie. a connection string to a storage blob? You can store those secrets in Azure KeyVault and securely reference said secrets in your function app.

The rest of this article is going to show you how to set this up without using Azure Portal.

If you want to learn more about how to better secure your function app, take a look at this article by Function PM Matthew

Pre-requisites

Azure CLI

Installation guide

jq

a lightweight and flexible command-line JSON processor that I promise you'll be using over and over again

A deployed function app

This can either be done through

  1. azure-cli

  2. Serverless framework - recommended since this article is building upon the sample app walk through from yesterday

Walk-through

All the scripts I mentioned below can be find in this accompanying repo

GitHub logo mydiemho / myho-serverless-demo

app to demo connecting Azure KeyVault using Serverless Framework

Feel free to change the chosen resource name in the scripts to something else, but beware that different resource have different naming restrictions.

Refer to the Azure resources naming convention guide if you're having trouble using
your desire values.


Log in

az account show # list all subscriptions you have access to 
az account set --subscription <SUB_ID> # id of the sub you want to use
az login
Enter fullscreen mode Exit fullscreen mode

Clone repo

git clone git@github.com:mydiemho/myho-serverless-demo.git
cd myho-serverless-demo
Enter fullscreen mode Exit fullscreen mode

Set up keyVault

./scripts/create-keyvault.sh
Enter fullscreen mode Exit fullscreen mode

The script will create a resource group and a keyVault.


Add secrets

./scripts/add-secrets.sh AwesomeSecret AwesomeSecretValue
Enter fullscreen mode Exit fullscreen mode

The script takes 2 inputs: the secret key and the secret value. If you do not pass in any inputs, the default key and value will be used.

Take note of the secret url in the output, you'll need it in a later step

Grant function app read permission

In order for the app the reference keyVault secrets, you have to add the app to the keyVault's access policies.

Behind the scene

The steps involved in doing this is:

  1. Adding a system-assigned identity to the function app 1

  2. Add this identity as access policy to keyVault

How-to

You'll have to first deploy a function app, then you can using the following script to grant access to the app

./scripts/grant-app-access.sh <APP_RESOURCE_GROUP> <APP_NAME>
Enter fullscreen mode Exit fullscreen mode

Once the script finish, you can check the portal and see that a new access policy has been added to the function app

KeyVault access policies portal


Add new app setting

We'll add the keyvault secret reference as an app setting *. App settings are available as environment variables to function handlers.

Using serverless, anything under the environment section will be created as app settings.

Make sure to replace the url with the one generated in add secrets


# see https://github.com/mydiemho/myho-serverless-demo/blob/master/serverless.yml#L29

  environment: # these will be created as application settings
    SUPER_SECRET: "@Microsoft.KeyVault(SecretUri=https://myho-serverless-demo-kv.vault.azure.net/secrets/MySuperSecretName/88df087331004326994047248b0b6b67)"

Enter fullscreen mode Exit fullscreen mode

Add new function

You can either update the handler code for one of the function or create a new function. For this example, I choose to create a new function called secrets.

update serverless.yml

add the following section to your yaml below existing functions


# see https://github.com/mydiemho/myho-serverless-demo/blob/master/serverless.yml#L93

  secrets:
    handler: src/handlers/secrets.printSecrets
    events:
      - http: true
        x-azure-settings:
          methods:
            - GET
          authLevel: anonymous
Enter fullscreen mode Exit fullscreen mode

add handler code

Add a new file src/handlers/secrets.js


# https://github.com/mydiemho/myho-serverless-demo/blob/master/src/handlers/secrets.js

"use strict";

const superSecret = process.env["SUPER_SECRET"];

module.exports.printSecrets = async function(context, req) {
  context.log(
    "JavaScript HTTP trigger function processed a request to display the secret in keyvault."
  );

  context.res = {
    // status: 200, /* Defaults to 200 */
    // FOR DEMO PURPOSE: DO NOT LOG SECRETS IN PRODUCTION
    body: `Shhhhh.. it's a secret: ${superSecret}`
  };
};

Enter fullscreen mode Exit fullscreen mode

Deploy new changes

Once you've done all the set up, you're now ready to test out your new function app that is referencing KeyVault

sls deploy
Enter fullscreen mode Exit fullscreen mode

If you're having trouble deploying, refer to this article to make sure you have done all the pre-requisites


Verify changes

After deploy, you can hit the function url, apim url, or using the invoke command to test your changes.

➜ sls invoke -f secrets                                                                             
Serverless: Logging into Azure

...

Serverless: Invoking function secrets with GET request
Serverless: "Shhhhh.. it's a secret: ItIsASecret"

Enter fullscreen mode Exit fullscreen mode
. . .