Introduction

At the end of last week (14 Sept 2017) Microsoft announced a new Azure Active Directory feature – Managed Service Identity. Managed Service Identity helps solve the chicken and egg bootstrap problem of needing credentials to connect to the Azure Key Vault to retrieve credentials. When used in conjunction with Virtual Machines, Web Apps and Azure Functions that meant having to implement methods to obfuscate credentials that were stored within them. I touched on one method that I’ve used a lot in this post here whereby I encrypt the credential and store it in the Application Settings, but it still required a keyfile to allow reversing of the encryption as part of the automation process. Thankfully those days are finally behind us.
I strongly recommend you read the Managed Service Identity announcement to understand more about what MSI is.
This post details using Managed Service Identity in PowerShell Azure Function Apps.

Enabling Managed Service Identity on your Azure Function App

In the Azure Portal navigate to your Azure Function Web App. Select it and then from the main-pane select the Platform Features tab then select Managed service identity.
Platform Features
Turn the toggle the switch to On for Register with Azure Active Directory then select Save.
ManagedServiceIdentity
Back in Platform Features under General Settings select Application Settings. 
General Settings
Under Application Settings you will see a subset of the environment variables/settings for your Function App. In my environment I don’t see the Managed Service Identity variables there. So lets keep digging.
App Settings
Under Platform Features select Console.
DevelopmentTools
When the Console loads, type Set. Scroll down and you should see MSI_ENDPOINT and MSI_SECRET.
NOTE: These variables weren’t immediately available in my environment. The next morning they were present. So I’m assuming there is a back-end process that populates them once you have enabled Managed Service Identity. And it takes more than a couple of hours 
Endpoint

Creating a New Azure Function App that uses Managed Service Identity

We will now create a new PowerShell Function App that will use Managed Service Identity to retrieve credentials from an Azure Key Vault.
From your Azure Function App, next to Functions select the + to create a New Function. I’m using a HttpTrigger PowerShell Function. Give it a name and select Create.
NewFunction
Put the following lines into the top of your function and select Save and Run.

# MSI Variables via Function Application Settings Variables
# Endpoint and Password
$endpoint = $env:MSI_ENDPOINT
$endpoint
$secret = $env:MSI_SECRET
$secret

You will see in the output the values of these two variables.
Vars

Key Vault

Now that we know we have Managed Service Identity all ready to go, we need to allow our Function App to access our Key Vault. If you don’t have a Key Vault already then read this post where I detail how to quickly get started with the Key Vault.
Go to your Key Vault and select Access Polices from the left menu list.
Vault
Select Add new, Select Principal and locate your Function App and click Select.
Access Policy 1
As my vault contains multiple credential types, I enabled the policy for Get for all types. Select Ok. Then select Save.
Policy - GET
We now have our Function App enabled to access the Key Vault.
Access Policy 2
Finally in your Key Vault, select a secret you want to retrieve via your Function App and copy out the Secret Identifier from the Properties.
Vault Secret URI

Function App Script

Here is my Sample PowerShell Function App script that will connect to the Key Vault and retrieve credentials. Line 12 should be the only line you need to update for your Key Vault Secret that you want to retrieve. Ensure you still have the API version at the end (which isn’t in the URI you copy from the Key Vault) /?api-version=2015-06-01

When run the output if you have everything correct will look below.
KeyVault Creds Output

Summary

We now have the basis of a script that we can use in our Azure Functions to allow us to use the Managed Service Identity function to connect to an Azure Key Vault and retrieve credentials. We’ve limited the access to the Key Vault to the Azure Function App to only GET the credential. The only piece of information we had to put in our Function App was the URI for the credential we want to retrieve. Brilliant.

Category:
Identity and Access Management, PowerShell
Tags:
, , ,

Join the conversation! 4 Comments

  1. Great article! I refactored this into a function so you can just call Get-AzureFunctionKeyVaultSecret
    function Get-AzureFunctionKeyVaultSecret {
    [CmdletBinding()]
    param (
    #The full URI to the key, you can copy and paste this from your Key properties in the Azure Portal
    [Parameter(Mandatory)]$SecretIdentifier
    )
    if (-not $EXECUTION_CONTEXT_FUNCTIONNAME) {write-error “Azure Function Environment not detected. This only works in Azure functions for now…”;return}
    # Managed Services Identity Variables
    if (-not $MSIEndpoint) {write-error “No Managed Services Identity detected. You must configure one first for your Azure Function. Details here: https://blog.kloud.com.au/2017/09/19/enabling-and-using-managed-service-identity-to-access-an-azure-key-vault-with-azure-powershell-functions/“;return}
    $MSIEndpoint = $env:MSI_ENDPOINT
    $MSISecret = $env:MSI_SECRET
    # Vault URI to get AuthN Token
    $vaultTokenURI = ‘https://vault.azure.net&api-version=2017-09-01’
    $vaultSecretURI = $secretIdentifier + ‘/?api-version=2015-06-01’
    # Create AuthN Header with our Function App Secret
    $header = @{‘Secret’ = $MSIsecret}
    # Get Key Vault AuthN Token
    $authenticationResult = Invoke-RestMethod -Method Get -Headers $header -Uri ($MSIEndpoint + ‘?resource=’ + $vaultTokenURI)
    $authenticationResult
    # Use Key Vault AuthN Token to create Request Header
    $requestHeader = @{ Authorization = “Bearer $($authenticationResult.access_token)” }
    # Call the Vault and retrieve credential object, return the result
    Invoke-RestMethod -Method GET -Uri $vaultSecretURI -ContentType ‘application/json’ -Headers $requestHeader
    }

  2. Thank you, Doc! I was struggling to understand why my call to the Key Vault was not working, working off Microsoft Azure documentation. Turns out, I was requesting an access token for the wrong resource (https://management.azure.com).
    Your PS code made it abundantly clear that I needed to request a token specifically for the key vault. Thanks again!

  3. I am wanting to generate a token for this resource=https://management.azure.com and its working only for system managed identity moreover the token generated is not getting any results if I try to list the subscriptions in an Enrollment Account. I created a owner role assignment for the system managed identity object id too yet no luck. Any suggestions?

Comments are closed.