{"id":9024,"date":"2024-01-31T09:11:10","date_gmt":"2024-01-31T09:11:10","guid":{"rendered":"https:\/\/cheapwindowsvps.com\/blog\/step-by-step-guide-to-linking-an-azure-function-or-web-app-to-a-key-vault-using-powershell\/"},"modified":"2025-01-20T11:35:08","modified_gmt":"2025-01-20T11:35:08","slug":"step-by-step-guide-to-linking-an-azure-function-or-web-app-to-a-key-vault-using-powershell","status":"publish","type":"post","link":"https:\/\/cheapwindowsvps.com\/blog\/step-by-step-guide-to-linking-an-azure-function-or-web-app-to-a-key-vault-using-powershell\/","title":{"rendered":"Step-by-Step Guide to Linking an Azure Function or Web App to a Key Vault using PowerShell"},"content":{"rendered":"<p><div>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.<\/div>\n<p>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.<\/p>\n<h2>The steps<\/h2>\n<p>Our Function app has a function with an HTTP trigger called &#8220;test.&#8221; We will have to follow these steps:<\/p>\n<\/p>\n<ol>\n<li>Set up the variables that we will use within the script<\/li>\n<li>Create a secret in an existing Key Vault named <em>supersecret<\/em><\/li>\n<li>Create a User Assigned Managed Identity (UAMI)<\/li>\n<li>Attach the UAMI to the Function app<\/li>\n<li>Assign the <em>Key Vault Secret Reader<\/em> role to the UAMI directly on the Key Vault Secret<\/li>\n<li>Configure the <em>Key Vault Reference Identity<\/em> property of the Function app to use UAMI when accessing the Key Vault<\/li>\n<li>Validate <em>keyVaultReferenceIdentity<\/em> config in the Function app<\/li>\n<li>Create an application setting (environment variable) in the Function app for retrieving the secret directly from the Key Vault<\/li>\n<\/ol>\n<p><p>Confirm the functionality by running the HTTP function to retrieve the secret value from Key Vault<\/p>\n<\/p>\n<p><h2>Set up variables<\/h2>\n<\/p>\n<p><p>Let&#8217;s configure our environment variables first.<\/p>\n<\/p>\n<p><pre><\/p><p># 0. Setting up variables<\/p><p>$functionAppName = \"RBACfuncapp1\"<\/p><p>$functionAppRG = \"rbac\"<\/p><p>$functionAppSub = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"<\/p><p>$KVName = \"certkv01\"<\/p><p>$KVRG = \"certs\"<\/p><p>$KVSub = \" xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"<\/p><p>$UAMIName = \"UAMItest\"<\/p><p>$UAMIRG = \"keyvaults\"<\/p><p>$UAMILocation = \"WestEurope\"<\/p><p>$secretName = \"supersecret\"<\/p><p>$secretValueText = \"SuperSecretInformation\"<\/p><p><\/pre>\n<\/p>\n<p><h2>Create a secret<\/h2>\n<\/p>\n<p><p>Below is the secret the Function app will use within the HTTP function.<\/p>\n<\/p>\n<p><pre><\/p><p># 1. Create a secret in an existing Key Vault<\/p><p>$secretvalue = ConvertTo-SecureString \"$($secretValueText)\" -AsPlainText -Force<\/p><p>$secret = Set-AzKeyVaultSecret -VaultName \"$($KVName)\" -Name \"$($secretName)\" -SecretValue $secretvalue<\/p><p><\/pre>\n<\/p>\n<p><div><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/A-secret-in-the-Key-Vault.png\" rel=\"nofollow noopener\" target=\"_blank\">A secret in the Key Vault<\/a><\/p>\n<p>A secret in the Key Vault<\/p>\n<\/div>\n<p><h2>Create a UAMI (User Assigned Managed Identity)<\/h2>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><pre># 2. Create a UAMI (User Assigned Managed Identity)<\/p><p>$UAMI = New-AzUserAssignedIdentity -Name \"$($UAMIName)\" -ResourceGroupName \"$($UAMIRG)\" -Location \"$($UAMILocation)\"<\/p><p>$UAMIID = $UAMI.id<\/p><p>$UAMIObjectID = ($UAMI).principalID<\/p><p><\/pre>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/A-new-UAMI-with-its-Client-ID-and-Object-ID.png\" rel=\"nofollow noopener\" target=\"_blank\">A new UAMI with its Client ID and Object ID<\/a><\/p>\n<p><h2>Attach the UAMI to the Function app<\/h2>\n<\/p>\n<p><p>Once the UAMI is attached to the Function app, it\u2019ll be visible under the Identity section.<\/p>\n<\/p>\n<p><pre><\/p><p># 3. Attach the UAMI to the function app<\/p><p>Update-AzFunctionApp -IdentityType UserAssigned -IdentityID $($UAMI.id) -ResourceGroupName \"$($functionAppRG)\" -Name \"$($functionAppName)\" -Force<\/p><p><\/pre>\n<\/p>\n<p><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/The-UAMI-has-been-associated-with-the-Function-app.png\" rel=\"nofollow noopener\" target=\"_blank\">The UAMI has been associated with the Function app<\/a><\/p>\n<p><h2>Assign a role to the identity<\/h2>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><pre><\/p><p># 4. Assign a role to the identity of the KV<\/p><p>New-AzRoleAssignment -Scope \"\/subscriptions\/$($KVSub)\/resourceGroups\/$($KVRG)\/providers\/Microsoft.KeyVault\/vaults\/$($KVName)\/secrets\/$($secretName)\" `<\/p><p>-ObjectId \"$($UAMIObjectID)\" `<\/p><p>-RoleDefinitionName 'Key Vault Secrets User'<\/p><p><\/pre>\n<p> <a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/The-UAMI-has-been-granted-permission-on-the-Key-Vault.png\" rel=\"nofollow noopener\" target=\"_blank\">The UAMI has been granted permission on the Key Vault<\/a> <\/p>\n<h2>Set up the Key Vault Reference Identity<\/h2>\n<p>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.<\/p>\n<\/p>\n<p><pre><\/p><p># 5. Set up the Key Vault Reference Identity to use UAMI to access the Key Vault<\/p><p>$functionAppResourceId = Get-AzFunctionApp <\/p><p>&nbsp;-ResourceGroupName $($functionAppRG) <\/p><p>&nbsp;-Name $($functionAppName) <\/p><p>&nbsp;| Select-Object -ExpandProperty Id<\/p><p>$Path = \"{0}?api-version=2021-01-01\" -f $functionAppResourceId<\/p><p>Invoke-AzRestMethod <\/p><p>&nbsp;-Method PATCH <\/p><p>&nbsp;-Path $Path <\/p><p>&nbsp;-Payload \"{'properties':{'keyVaultReferenceIdentity':'$UAMIID'}}\"<\/p><p><\/pre>\n<\/p>\n<p><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/Setting-up-the-keyVaultReferenceIdentity-on-the-Function-app.png\" rel=\"nofollow noopener\" target=\"_blank\">Setting up the keyVaultReferenceIdentity on the Function app<\/a><\/p>\n<p><h2>Validate keyVaultReferenceIdentity config<\/h2>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><pre><\/p><p># 6. Validate keyVaultReferenceIdentity config on the Function app<\/p><p>Invoke-AzRestMethod `<\/p><p>-Uri \"https:\/\/management.azure.com\/subscriptions\/$($functionAppSub)\/resourceGroups\/RBAC\/providers\/Microsoft.Web\/sites\/RBACfuncapp1?api-version=2020-12-01\" `<\/p><p>| select -ExpandProperty content `<\/p><p>| convertfrom-json `<\/p><p>| select -ExpandProperty properties `<\/p><p>| select keyVaultReferenceIdentity `<\/p><p>| fl *<\/p><p><\/pre>\n<\/p>\n<p><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/Validating-the-keyVaultReferenceIdentity.png\" rel=\"nofollow noopener\" target=\"_blank\">Validating the keyVaultReferenceIdentity<\/a><\/p>\n<p><h2>Create an application setting<\/h2>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><pre>\"@Microsoft.KeyVault(VaultName=$($KVName);SecretName=$($secretName);SecretVersion=$($secret.version))\"}<\/p><p><\/pre>\n<\/p>\n<p><pre><\/p><p># 7. Create an application setting (environment variable) on the Function app for retrieving the secret directly from the Key Vault<\/p><p>Update-AzFunctionAppSetting -Name $($functionAppName) <\/p><p>-ResourceGroupName $($functionAppRG) <\/p><p>-SubscriptionId \"$($functionAppSub)\" <\/p><p>-AppSetting @{\"secret\" = \"@Microsoft.KeyVault(VaultName=$($KVName);SecretName=$($secretName);SecretVersion=$($secret.version))\"}<\/p><p><\/pre>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><p>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&#8217;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.<\/p>\n<\/p>\n<p><div><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/Creating-a-new-application-setting-with-a-reference-to-a-specific-Key-Vault-secret.png\" rel=\"nofollow noopener\" target=\"_blank\">Creating a new application setting with a reference to a specific Key Vault secret<\/a><\/p>\n<p>Creating a new application setting with a reference to a specific Key Vault secret<\/p>\n<\/div>\n<p><h2>Confirming the functionality<\/h2>\n<\/p>\n<p><p>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.<\/p>\n<\/p>\n<p><div><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/Running-a-test-with-an-HTTP-function-using-the-Client-ID-of-the-UAMI-to-get-the-secret-from-the-Key-Vault.png\" rel=\"nofollow noopener\" target=\"_blank\">Running a test with an HTTP function using the Client ID of the UAMI to get the secret from the Key Vault<\/a><\/p>\n<p>Running a test with an HTTP function using the Client ID of the UAMI to get the secret from the Key Vault<\/p>\n<\/div>\n<p><p>Once we hit <strong>Run<\/strong>, the Function app will retrieve the secret value from the Key Vault.<\/p>\n<div>\n<h2>Subscribe to 4sysops newsletter!<\/h2>\n<\/div>\n<div><a href=\"https:\/\/4sysops.com\/wp-content\/uploads\/2024\/01\/The-result-will-be-the-desired-secret-retrieved-from-the-Key-Vault-securely.png\" rel=\"nofollow noopener\" target=\"_blank\">The result will be the desired secret retrieved from the Key Vault securely<\/a><\/p>\n<p>The result will be the desired secret retrieved from the Key Vault securely<\/p>\n<\/div>\n<h2>Conclusion<\/h2><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-9024","post","type-post","status-publish","format-standard","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/posts\/9024","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/comments?post=9024"}],"version-history":[{"count":1,"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/posts\/9024\/revisions"}],"predecessor-version":[{"id":10203,"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/posts\/9024\/revisions\/10203"}],"wp:attachment":[{"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/media?parent=9024"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/categories?post=9024"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cheapwindowsvps.com\/blog\/wp-json\/wp\/v2\/tags?post=9024"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}