DEV Community

Cover image for Protect secrets in Azure Functions using Key Vault
Marcel.L
Marcel.L

Posted on • Edited on

Protect secrets in Azure Functions using Key Vault

What is an Azure function?

Azure Functions is a cloud service available on-demand that provides all the continually updated infrastructure and resources needed to run your applications. You focus on the pieces of code that matter most to you, and Functions handles the rest. Functions provides serverless compute for Azure. You can use Functions to build web APIs, respond to database changes, process IoT streams, manage message queues, and more.

What is Azure Key Vault?

Azure Key Vault is a cloud service that allows us to protect cryptographic keys, certificates (and the private keys associated with certificates), and secrets (such as connection strings and passwords) in the cloud.

How to integrate Key Vault with Azure Functions

Because Azure functions are serverless pieces of code, we do not want to put any of our secrets (such as passwords or connection strings) into our function code in plain-text. For security reasons we need to protect the secrets we use in our function code to not expose sensitive information. So today we will look at how we can create a function app using PowerShell Core as the code base, and protect any secrets that we use in our function code with Azure Key Vault.

To get everything ready I will be using Azure CLI in a powershell console. First we will log into Azure by running:

az login
Enter fullscreen mode Exit fullscreen mode

Next we will create a resource group, storage account, key vault, app service plan and function app by running:

# Variables - Function app and storage account names must be unique.
$randomInt = Get-Random -Maximum 9999
$resourceGroupName = "KeyVaultFunction"
$functionAppName = "func$randomInt"
$storageName = "sa$functionAppName"
$kvName = "kv$functionAppName"
$region = "uksouth"

# Create a resource resourceGroupName
az group create --name "$resourceGroupName" --location "$region"

# Create an azure storage account
az storage account create `
    --name "$storageName" `
    --location "$region" `
    --resource-group "$resourceGroupName" `
    --sku "Standard_LRS" `
    --kind "StorageV2"

# Create an azure key vault (RBAC model)
az keyvault create `
    --name "$kvName" `
    --resource-group "$resourceGroupName" `
    --location "$region" `
    --enable-rbac-authorization

# Create a Function App
az functionapp create `
    --name "$functionAppName" `
    --storage-account "$storageName" `
    --consumption-plan-location "$region" `
    --resource-group "$resourceGroupName" `
    --os-type "Windows" `
    --runtime "powershell" `
    --runtime-version "7.0" `
    --functions-version "3"
Enter fullscreen mode Exit fullscreen mode

Next we will enable the function app with a system assigned managed identity so that we can permission our function app to access our key vault.

Under the function app settings pane select Identity and enable the system assigned setting to be ON and save the setting:

managedIdentity-01

With the managed identity now created, we can add a role assignment and permissions (IAM) to our key vault. We will give the function identity the role Key Vault Secrets User because we only want the function to be able to retrieve secrets.

On the same settings pane where we set the identity you will now see a new setting called Permissions. Click on Azure Role Assignments and add the relevant permissions on the key vault.

Note: You can also add the role assignment permissions on the key vault by going to the key vault and select IAM on the key vault directly.

managedIdentity-02

managedIdentity-03

We can also check the IAM permissions under our key vault for our function app:

iam

Create some secrets in the key vault for testing:

Name Value
SecUser01 pwd9000admin
SecPass01 S8p3r$3cR3t2021!*!

kvsecrets

Now we will configure our function app to reference our key vault secrets and test the solution.

We will use the following Reference syntax.

@Microsoft.KeyVault(VaultName=<myVault>;SecretName=<mySecret>;SecretVersion=<secretVersion>)
Enter fullscreen mode Exit fullscreen mode

In addition you can reference a key vault secret using the URI:

@Microsoft.KeyVault(SecretUri=https://<key-vault-name>.vault.azure.net/secrets/<secret-name>/<secret-version>)
Enter fullscreen mode Exit fullscreen mode

NOTE: If you want the reference to always take the latest version of the secret from Key Vault, then put the secret identifier URL to the SecretUri, and simply omit the secret version like below. Make sure that the URI MUST end with the trailing slash (/).

@Microsoft.KeyVault(SecretUri=https://<key-vault-name>.vault.azure.net/secrets/<secret-name>/)
Enter fullscreen mode Exit fullscreen mode

Under our function Settings pane select Configuration and add two new Application settings:

app-settings-1

app-settings-2

app-settings-3

Under the Functions pane click Add with the following settings: function-add

Name Value
Development Environment Develop in portal
Select a template HTTP trigger
New Function keyvaultdemo
Authorization level Function

Next under Code + Test copy the following powershell code:

using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
    $name = $Request.Body.Name
}

$body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."

$User = $ENV:kv_SecUser01
$Pass = $ENV:kv_SecPass01

Write-Host "Username retrieved from key vault: $User"
Write-Host "Password retrieved from key vault: $Pass"

if ($name) {
    $body = "Hello, $name. This HTTP triggered function executed successfully."
}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = [HttpStatusCode]::OK
    Body = $body
})
Enter fullscreen mode Exit fullscreen mode

Here is also a Link to the function code.

Note: Our secret references that we configured on the functions application settings are loaded into environment variables as you can see from the function code above:

$User = $ENV:kv_SecUser01
$Pass = $ENV:kv_SecPass01

Write-Host "Username retrieved from key vault: $User"
Write-Host "Password retrieved from key vault: $Pass"
Enter fullscreen mode Exit fullscreen mode

Testing our function app

Let's test our function app by triggering the code manually using Test/Run to see if our function can retrieve our secrets we specified.

log-01

I hope you have enjoyed this post and have learned something new. You can also find the code samples used in this blog post on my GitHub page. ❤️

Author

Like, share, follow me on: 🐙 GitHub | 🐧 X/Twitter | 👾 LinkedIn

Top comments (0)