0 Comments Posted in:

Yesterday, I showed how we can deploy Azure Functions with the Azure CLI. Today, I want to build on that and show how we can use the Azure CLI to add a "Managed Service Identity" (apparently now known simply as "Managed Identity") to a Function App, and then use that identity to grant our Function App access to a secret stored in Azure Key Vault.

And again I'll show you how the entire thing can be automated with the Azure CLI.

Step 1 - Create the Function App

The first step is to create our Function App, for which we need a Resource Group, a Storage Account, and an App Service Plan. I covered this in more detail yesterday, but here's the basic Azure CLI commands to provision a new Function App running on the consumption plan.

# create a resource group
$resourceGroup = "AzureFunctionsMsiDemo"
$location = "westeurope"
az group create -n $resourceGroup -l $location

# create a storage account
$rand = Get-Random -Minimum 10000 -Maximum 99999
$storageAccountName = "funcsmsi$rand"

az storage account create `
  -n $storageAccountName `
  -l $location `
  -g $resourceGroup `
  --sku Standard_LRS

# create a function app
$functionAppName = "funcs-msi-$rand"

az functionapp create `
  -n $functionAppName `
  --storage-account $storageAccountName `
  --consumption-plan-location $location `
  --runtime dotnet `
  -g $resourceGroup

Step 2 - Assign a managed identity

We can use the az functionapp identity assign command to create a "system assigned" managed identity for this Function App.

az functionapp identity assign -n $functionAppName -g $resourceGroup

The response will include the principalId and tenantId, and we can get hold of them later if we need to with the following commands:

$principalId = az functionapp identity show -n $functionAppName -g $resourceGroup --query principalId -o tsv
$tenantId = az functionapp identity show -n $functionAppName -g $resourceGroup --query tenantId -o tsv

We can also find this identity in Azure Active Directory with the following commands (Note that the "principal Id is also sometimes called the "object id"):

az ad sp show --id $principalId
# or
az ad sp list --display-name $functionAppName

Assigning an identity to our Function App means we'll have two new environment variables MSI_ENDPOINT and MSI_SECRET which enable applications to easy get an authentication token for this identity. However, we won't need to directly use them in this example.

Step 3 - Create a Key Vault and Store a Secret

You may already have a Key Vault available to you, but if not, the Azure CLI enables you easily to create one. For the purposes of this demo, let's create a new Key Vault in the same resource group and add a secret to it.

# Create a key vault
$keyvaultname = "funcsmsi$rand"
az keyvault create -n $keyvaultname -g $resourceGroup

# Save a secret in the key vault
$secretName = "MySecret"
az keyvault secret set -n $secretName --vault-name $keyvaultname `
            --value "Super secret value!"

# view the secret
az keyvault secret show -n $secretName --vault-name $keyvaultname

Each secret has an identifier in the form of a URL, and we'll need it in order to access the secret value. Here's how we can get the identifier for our secret:

$secretId = az keyvault secret show -n $secretName `
        --vault-name $keyvaultname --query "id" -o tsv

Step 4 - Grant the Managed Identity Read Access to Key Vault

By default, the managed identity for our function app cannot access Key Vault. We can grant it access for reading secrets only with the following command:

az keyvault set-policy -n $keyvaultname -g $resourceGroup `
            --object-id $principalId --secret-permissions get

# to see the access policies added:
az keyvault show -n $keyvaultname -g $resourceGroup `
            --query "properties.accessPolicies[?objectId == ``$principalId``]"

Step 5 - Add Application Settings referencing Key Vault secrets

To access secrets in Key Vault from our Function App we can create application settings whose value has the form @Microsoft.KeyVault(SecretUri=https://my-key-vault.vault.azure.net/secrets/my-secret/29e8f1b62cb34f3aa40f0757aea0388d).

Although it is possible to set these secrets using the Azure CLI, it's a pain because it gets into a mess escaping the secret value (or at least does so from PowerShell). I found I needed to use the rather obscure ^^ escape sequence to ensure that the final ) character made it into my function app settings:

az functionapp config appsettings set -n $functionAppName -g $resourceGroup `
    --settings "[email protected](SecretUri=$secretId^^)"

When an app setting is defined like this, the Azure Functions runtime will use the Managed Identity to access the Key Vault and read the secret.

Step 6 - Accessing the secrets in Azure Functions

Once we've set this all up, an Azure Function can simply access the secret by reading the environment variable with the app setting name. Here's a very simple Azure Function I made to test this that simply allows you to access any environment variable.

[FunctionName("GetAppSetting")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
    ILogger log)
{
    string settingName = req.Query["name"];
    if (string.IsNullOrEmpty(settingName))
        return new BadRequestObjectResult("Please pass a name on the query string");

    log.LogInformation($"Requesting setting {settingName}.");
    var value = Environment.GetEnvironmentVariable(settingName);
    return new OkObjectResult($"{settingName}={value}");
}

So if you call this function and pass a name query string parameter of Secret1, you'll get the value stored in the Key Vault secret. You can also call it passing a name of MSI_ENDPOINT or MSI_SECRET to see the value of the environment variables that were added as a result of enabling a system managed identity.

Summary

Managed Identities simplify the work required to grant your Function Apps the right to access secrets in Key Vault, and the whole process can be automated with the Azure CLI. To read more on using secrets in Key Vault with Azure Functions, check out this article by Jeff Hollan. And you can access my entire demo PowerShell script here which includes the additional steps of deploying the sample Function App, and using Kudu to get the function key so you can even automate calling the Azure Function without needing to go to the portal first to find the function key.

Want to learn more about how easy it is to get up and running with Azure Functions? Be sure to check out my Pluralsight courses Azure Functions Fundamentals and Microsoft Azure Developer: Create Serverless Functions
Vote on HN