Step-by-Step Guide to Linking an Azure Function or Web App to a Key Vault using PowerShell

Azure Functions often require access to sensitive information. It is a security risk to store credentials in code or configuration files. Thus, protecting sensitive information like connection strings, API keys, or passwords is crucial. This is where Azure Key Vault comes in, offering secure and centralized storage for all your secrets. In this article, I will explain how to retrieve secrets from the Key Vault within an Azure Function using PowerShell.

Although several methods exist to retrieve secrets from a Key Vault, utilizing environment variables through Application Settings in Function apps proves to be one of the highly effective methods. This approach not only enables secure access to secrets within Azure Functions but also eliminates the need to hardcode them.

The steps

Our Function app has a function with an HTTP trigger called “test.” We will have to follow these steps:

  1. Set up the variables that we will use within the script
  2. Create a secret in an existing Key Vault named supersecret
  3. Create a User Assigned Managed Identity (UAMI)
  4. Attach the UAMI to the Function app
  5. Assign the Key Vault Secret Reader role to the UAMI directly on the Key Vault Secret
  6. Configure the Key Vault Reference Identity property of the Function app to use UAMI when accessing the Key Vault
  7. Validate keyVaultReferenceIdentity config in the Function app
  8. Create an application setting (environment variable) in the Function app for retrieving the secret directly from the Key Vault

Confirm the functionality by running the HTTP function to retrieve the secret value from Key Vault

Set up variables

Let’s configure our environment variables first.

# 0. Setting up variables

$functionAppName = "RBACfuncapp1"

$functionAppRG = "rbac"

$functionAppSub = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

$KVName = "certkv01"

$KVRG = "certs"

$KVSub = " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

$UAMIName = "UAMItest"

$UAMIRG = "keyvaults"

$UAMILocation = "WestEurope"

$secretName = "supersecret"

$secretValueText = "SuperSecretInformation"

Create a secret

Below is the secret the Function app will use within the HTTP function.

# 1. Create a secret in an existing Key Vault

$secretvalue = ConvertTo-SecureString "$($secretValueText)" -AsPlainText -Force

$secret = Set-AzKeyVaultSecret -VaultName "$($KVName)" -Name "$($secretName)" -SecretValue $secretvalue

A secret in the Key Vault

A secret in the Key Vault

Create a UAMI (User Assigned Managed Identity)

This identity will be associated with the Function app. We will assign a proper role to the Key Vault Secret so that the function can access the secret. Thus, the UAMI will represent the Function app in its interactions with the Key Vault.

# 2. Create a UAMI (User Assigned Managed Identity)

$UAMI = New-AzUserAssignedIdentity -Name "$($UAMIName)" -ResourceGroupName "$($UAMIRG)" -Location "$($UAMILocation)"

$UAMIID = $UAMI.id

$UAMIObjectID = ($UAMI).principalID

Once a UAMI is available, a Client ID and an Object ID are automatically created. In the next step, we will use the Object ID to attach the UAMI to the Function app. The ClientID, however, will be used within the function code later to authenticate the function against Azure.

A new UAMI with its Client ID and Object ID

Attach the UAMI to the Function app

Once the UAMI is attached to the Function app, it’ll be visible under the Identity section.

# 3. Attach the UAMI to the function app

Update-AzFunctionApp -IdentityType UserAssigned -IdentityID $($UAMI.id) -ResourceGroupName "$($functionAppRG)" -Name "$($functionAppName)" -Force

The UAMI has been associated with the Function app

Assign a role to the identity

The Key Vault Secrets user role will be assigned directly to the UAMI of the KEY Vault secret and NOT to the entire Key Vault. This way, the UAMI can only access the specified secret on the Key Vault without access to other entities such as other secrets, keys, or certificates.

# 4. Assign a role to the identity of the KV

New-AzRoleAssignment -Scope "/subscriptions/$($KVSub)/resourceGroups/$($KVRG)/providers/Microsoft.KeyVault/vaults/$($KVName)/secrets/$($secretName)" `

-ObjectId "$($UAMIObjectID)" `

-RoleDefinitionName 'Key Vault Secrets User'

The UAMI has been granted permission on the Key Vault

Set up the Key Vault Reference Identity

Since we want to use a User Assigned Managed Identity to access the Key Vault, we need to set the Function app property keyVaultReferenceIdentity to use the UAMI for Key Vault operations. This way, the Function app will use the UAMI attached to it, and NOT a System Assigned Managed Identity to make calls toward the Key Vault.

# 5. Set up the Key Vault Reference Identity to use UAMI to access the Key Vault

$functionAppResourceId = Get-AzFunctionApp

 -ResourceGroupName $($functionAppRG)

 -Name $($functionAppName)

 | Select-Object -ExpandProperty Id

$Path = "{0}?api-version=2021-01-01" -f $functionAppResourceId

Invoke-AzRestMethod

 -Method PATCH

 -Path $Path

 -Payload "{'properties':{'keyVaultReferenceIdentity':'$UAMIID'}}"

Setting up the keyVaultReferenceIdentity on the Function app

Validate keyVaultReferenceIdentity config

With the following command, we can validate the configuration and confirm that the Function app will use the UAMI specified in the previous step to access the Key Vault.

# 6. Validate keyVaultReferenceIdentity config on the Function app

Invoke-AzRestMethod `

-Uri "https://management.azure.com/subscriptions/$($functionAppSub)/resourceGroups/RBAC/providers/Microsoft.Web/sites/RBACfuncapp1?api-version=2020-12-01" `

| select -ExpandProperty content `

| convertfrom-json `

| select -ExpandProperty properties `

| select keyVaultReferenceIdentity `

| fl *

Validating the keyVaultReferenceIdentity

Create an application setting

We will use the command below to create a new application setting, also called an environment variable, on the Function app. This connectionString-like reference allows Function apps to communicate with Key Vaults using the Managed identity without exposing authentication credentials.

"@Microsoft.KeyVault(VaultName=$($KVName);SecretName=$($secretName);SecretVersion=$($secret.version))"}

# 7. Create an application setting (environment variable) on the Function app for retrieving the secret directly from the Key Vault

Update-AzFunctionAppSetting -Name $($functionAppName)

-ResourceGroupName $($functionAppRG)

-SubscriptionId "$($functionAppSub)"

-AppSetting @{"secret" = "@Microsoft.KeyVault(VaultName=$($KVName);SecretName=$($secretName);SecretVersion=$($secret.version))"}

If a secret version is not specified in the reference, the app will automatically utilize the most recent version in the Key Vault. This ensures that the Function app always uses the latest version, even if newer versions are added due to a rotation event.

This update process occurs within 24 hours of the new version becoming available. App Service caches Key Vault references for 24 hours before re-fetching. If any changes are made to the app’s configuration before this period, the app will restart and immediately re-fetch all referenced secrets. This guarantees that changes to the referenced secrets are promptly reflected in the Function app.

Creating a new application setting with a reference to a specific Key Vault secret

Creating a new application setting with a reference to a specific Key Vault secret

Confirming the functionality

First, we will use the UAMI client ID within the function code to authenticate against Azure. We will provide the Client ID as an input in the request body.

Running a test with an HTTP function using the Client ID of the UAMI to get the secret from the Key Vault

Running a test with an HTTP function using the Client ID of the UAMI to get the secret from the Key Vault

Once we hit Run, the Function app will retrieve the secret value from the Key Vault.

Subscribe to 4sysops newsletter!

The result will be the desired secret retrieved from the Key Vault securely

The result will be the desired secret retrieved from the Key Vault securely

Conclusion


Posted

in

by

Tags: