Creating Azure functions with Python and accessing the Azure Key Vault for secrets.

Posted on Tue 20 August 2019 in Azure, python

Creating and using key vault with Azure functions (and Python!)

This week I needed to solve a problem, and this was creating an API proxy (for various reason I won't go into here)

Essentially we needed to hide our API keys from the systems calling the API's and there was not an easy way of doing this with the tools available to us on a front end system (BigCommerce, I'm looking at you)

So, we decided to proxy the requests and only expose certain routes to the front end of the website.

This seemed a great use of Azure functions, and within 10 minutes I had one up and running , serving some data.

It then took me the best part of a day, to piece together all the information to use the Azure Key Vault with the Azure Function.

Here is how to do it, so I don't forget again! (And maybe help someone in the future! - hello future me.)

Overview of the process. (a TLDR; if you will)

  1. Config VSCode with the Azure Functions plugin
  2. Config VSCode with the Python plugin
  3. Create a function, and upload with VSCode
  4. Create a Managed Identify for the AzureFunctions
  5. Create a Key Vault
  6. Store your Secreats in the vault
  7. Apply the Managed Identify for your AzureFunctions app to be able to access this vault
  8. Tell your Azure function that there are secrets available and provide the unique secret ID wrapped in @Microsoft.KeyValut({SECRET_URI})
  9. Access these via os.environ in your function.

How to configure the lot:

Setting up VSCode to work with Azure functions.

The process is pretty simple for setting this up, the instructions in VSCode for installing and configuring work really well, there is not much to add here.

There is a great demo video to watch here: Microsoft VSCode setup

The only thing you will need to change to get your hidden vault API keys is to grab them from the environment variables that will be injected into the system at run time.

For our example we will use API-KEY - its worth noting Azure do not seem to accept underscores for anything.

An example Azure function for this would be:

import logging

import azure.functions as func
import os
import json

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')
    env = os.environ
    env_dict = dict(env)
    env_json = json.dumps(env_dict)
    return func.HttpResponse(f"ENVVARS:\n {env_json}")

This will output ALL the environment variables to the browser to show you what you have.

So to grab you API-KEY would just be as simple as

os.environ['API-KEY']

or to handle errors better

api_key = os.getenv('API-KEY')

if not api_key:
    raise Exception('No API Key Found')

and handle the exception gracefully.

Then simply upload this to Azure and run!

You should get an error that there is no API-KEY - this is because we have not provided this in a key vault.

Enable Managed service identity for the Azure Function

From the Main Azure function - select Platform features > All settings > identity

This has now added this as an object in the Azure active directory, allowing it to be granted access priviliges to the key vault

Create a Key Vault

  • Go to Key Vaults in azure, and make a new one
  • Select Access control
  • Select a role type of Reader (Unless you want your function to create or modify keys - here we just need access to them
  • For Assign access to, choose App Service - NOT FUNCTION APP` this was what tripped me up as it will not show your managed service identity.
  • You should now see (or be able to search) for your Azure function here, select it.
  • Save

Add a secret to the key vault

  • Select settings from the left under the key vault we have just made
  • Click Generate / Import,
    • Give the secret a name API-KEY
    • Give the secret a value mysupersecretvalue
    • Make sure it is enabled and save
  • Click on the newly generated secret
    • Click on the current version
    • copy the secret identifier this should look something like https://MYVAULTNAME.vault.azure.net/secrets/APIKEY/xxxxxxxxxxxxxxxx (where xx is the unique version)

Our work here is done.

Make our Azure function access the key vault and extract the secret

  • Go back to our Function, (under the function app)
  • Select manage
  • Under function keys add a new one
    • provide a name (this does not appear to need to mirror the secret name)
    • for the value wrap the secret identifier with @Microsoft.KeyValut({ })
    • your value should look like @Microsoft.KeyVault(SecretUri=https://mydomainkeyvault.vault.azure.net/secrets/APIKEY/longstringofid)
    • Save

Finally

Run your azure function - your API-KEY should be visible and working :)

I'm fairly sure there are ways to automate the key store and get latest versions etc, but thats for another day.

I'll update this with images and links to some really helpful websites ASAP, but thats the process for now!