简体   繁体   中英

Get Webhook url of a Function App in ARM to use for Event Grid Subscription

I am trying to automate the deployment of our environment vir ARM templates. I can deploy Event Grid and Function Apps but now I need to subscribe the function app to the Event Grid after the function app is deployed. Is there a way to get the webhook url for the function app

  1. Via a ARM
  2. Some other component (Powershell) in the Release pipeline

We are able to create the subscription via ARM once we have the webhook url - but to get to the correct url seems to be where we are falling of the boat.

Any help please

I managed to get this working with the help of the answers from @Van and @Barrie above.

This script returns the masterkey and defaultkey from the azure api, which enables you to create an eventgrid subscription from a functionApp/webApp in your release pipeline.

Van's script (30 Jul) worked with FA version 1 but it did not work for FunctionApps V2 (something was changed in the api). When using this script in V2 the error was:

Runtime keys are stored on blob storage. This API doesn't support this configuration. Please change Environment variable AzureWebJobsSecretStorageType value to 'Files'.

I amended this script and now it works with V2:

#DEBUG: when debugging (running in powershell on local pc) you need to comment out the next line by starting the line with #
param($resourceGroupName, $webAppname)

function Get-PublishingProfileCredentials($resourceGroupName, $webAppName){
        $resourceType = "Microsoft.Web/sites/config"
        $resourceName = "$webAppName/publishingcredentials"
        $publishingCredentials = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType $resourceType -ResourceName $resourceName -Action list -ApiVersion 2015-08-01 -Force
        return $publishingCredentials
}

function Get-KuduApiAuthorisationHeaderValue($resourceGroupName, $webAppName){
        $publishingCredentials = Get-PublishingProfileCredentials $resourceGroupName $webAppName
        return ("Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $publishingCredentials.Properties.PublishingUserName, $publishingCredentials.Properties.PublishingPassword))))
}

function Get-MasterAPIKey($kuduApiAuthorisationToken, $webAppName ){    
        $bearerToken = Invoke-RestMethod -Uri https://$webAppName.scm.azurewebsites.net/api/functions/admin/token  -Headers @{"Authorization"=$kuduApiAuthorisationToken;"If-Match"="*"} 

        $masterkeyResponse = Invoke-RestMethod -Method GET -Headers @{Authorization=("Bearer {0}" -f $bearerToken)} -Uri "https://$webAppName.azurewebsites.net/admin/host/systemkeys/_master" 
        $masterKeyValue = $masterkeyResponse.value
        return $masterKeyValue
}

function Get-HostAPIKeys($kuduApiAuthorisationToken, $webAppName, $masterKey ){
        $apiUrl = "https://$webAppName.azurewebsites.net/admin/host/keys?code=$masterKey"
        $result = Invoke-WebRequest $apiUrl
        return $result
}

#DEBUG: when debugging this in powershell on my local pc I use this to authenticate (remove # to uncomment the next line):
#Login-AzureRmAccount -SubscriptionName "Insert_Subscription_Name_Here"


#DEBUG: when debugging you need to set these parameters:
# $resourceGroupName = "Insert_ResourceGroup_Name_Here"
# $webAppname = "Insert_FunctionApp_Name_Here"


#Auth Header
$kuduToken = Get-KuduApiAuthorisationHeaderValue $resourceGroupName $webAppName

#MasterKey
$masterKey = Get-MasterAPIKey $kuduToken $webAppName
Write-Host "masterKey = " $masterKey

#Default Key
$result = Get-HostAPIKeys $kuduToken $webAppName $masterkey
$keysCode =  $result.Content | ConvertFrom-Json
Write-Host "default Key = " $keysCode.Keys[0].Value

#Set Return Values:
$faMasterKey = $masterkey
$faDefaultKey = $keysCode.Keys[0].Value

Write-Output ("##vso[task.setvariable variable=fa_MasterKey;]$faMasterKey")
Write-Output ("##vso[task.setvariable variable=fa_DefaultKey;]$faDefaultKey")

There is only a small difference between this script and Van's script. The major difference is that this script will work on Azure CLI Functions V2. More info: https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-grid

You should be able to output the webhook URL like this:

"outputs": {       
    "Url": {
        "type": "string",
        "value": "[listsecrets(resourceId('Microsoft.Web/sites/functions', parameters('yourFunctionAppName'), parameters('yourFunctionName')),'2015-08-01').trigger_url]"
    }        
}

Here is a related answer .

I finally managed to get this working. In the end I created a powershell task that extracted the masterkey (and defaultKey) and now I am able to create my eventgrid subscriptions.

Thanks to

Here is the powershell script I use:

param($resourceGroupName, $webAppname)

function Get-PublishingProfileCredentials($resourceGroupName, $webAppName){

$resourceType = "Microsoft.Web/sites/config"
$resourceName = "$webAppName/publishingcredentials"
$publishingCredentials = Invoke-AzureRmResourceAction -ResourceGroupName 
$resourceGroupName -ResourceType $resourceType -ResourceName $resourceName -Action 
list -ApiVersion 2015-08-01 -Force
return $publishingCredentials   
}

function Get-KuduApiAuthorisationHeaderValue($resourceGroupName, $webAppName){

$publishingCredentials = Get-PublishingProfileCredentials $resourceGroupName $webAppName
return ("Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $publishingCredentials.Properties.PublishingUserName, $publishingCredentials.Properties.PublishingPassword))))
}

function Get-MasterAPIKey($kuduApiAuthorisationToken, $webAppName ){

$apiUrl = "https://$webAppName.scm.azurewebsites.net/api/functions/admin/masterkey"

$result = Invoke-RestMethod -Uri $apiUrl -Headers @{"Authorization"=$kuduApiAuthorisationToken;"If-Match"="*"} 

return $result`
}

function Get-HostAPIKeys($kuduApiAuthorisationToken, $webAppName, $masterKey ){

$apiUrl = "https://$webAppName.azurewebsites.net/admin/host/keys?code=$masterKey"

$result = Invoke-WebRequest $apiUrl

return $result`
}

$accessToken = Get-KuduApiAuthorisationHeaderValue $resourceGroupName $webAppname

$adminCode = Get-MasterAPIKey $accessToken $webAppname

Write-Host "masterKey = " $adminCode.Masterkey

$result = Get-HostAPIKeys $accessToken $webAppname $adminCode.Masterkey

$keysCode =  $result.Content | ConvertFrom-Json

Write-Host "default Key = " $keysCode.Keys[0].Value

$faMasterKey = $adminCode.Masterkey
$faDefaultKey = $keysCode.Keys[0].Value

Write-Output ("##vso[task.setvariable variable=fa_MasterKey;]$faMasterKey")
Write-Output ("##vso[task.setvariable variable=fa_DefaultKey;]$faDefaultKey")

This will output the:

  • masterkey in the 'fa_MasterKey' variable
  • defaultKey in the 'fa_DefaultKey' variable

(I am going to attempt to create a VSTS task and publsih it to the marketplace - details will follow)

I was in the same boat as you and eventually got this working but it took quite a bit of time to work out the correct endpoints etc. What I was trying to do is create an event subscription for one of my resource groups using az eventgrid event-subscription create . The main issue was with the --endpoint argument as that has a code query string parameter on it. I could find this in the Azure portal quite easily by doing this:

  1. Go to my function app
  2. Go to the function I want to add as handler for the event subscription
  3. Click "Add Event Grid subscription"
  4. Copy the "Subscriber Endpoint" value

However, I wanted to do this all programmatically which proved to be difficult. In the end, the bash script I used looks like this:

#!/bin/bash

appName="myfunctionappname"
resourceGroup="myresourcegroupname"

# First do a KUDU login so we can get a JWT bearer token
user=$(az webapp deployment list-publishing-profiles -n $appName -g $resourceGroup --query "[?publishMethod=='MSDeploy'].userName" -o tsv)
pass=$(az webapp deployment list-publishing-profiles -n $appName -g $resourceGroup --query "[?publishMethod=='MSDeploy'].userPWD" -o tsv)
bearerToken=$(curl -s -u $user:$pass https://$appName.scm.azurewebsites.net/api/functions/admin/token | tr -d '"')

# Creating event grid subscription linked against the endpoint is an admin function so requires a master key
masterKeyResponse=$(curl -s -H "Authorization: Bearer $bearerToken" "https://$appName.azurewebsites.net/admin/host/systemkeys/_master")
masterKey=$(echo $masterKeyResponse | jq '.value' | tr -d '"')

functionName="MyFunctionName"
az eventgrid event-subscription create -g $resourceGroup --name "test-event-subscription" --endpoint "https://$appName.azurewebsites.net/runtime/webhooks/EventGridExtensionConfig?functionName=$functionName&code=$masterKey"

For V 2.0 and 3.0 Function Apps you must set AzureWebJobsSecretStorageType to files:

  "properties": {
    "name": "[variables('functionsName')]",
    "siteConfig": {
      "appSettings": [
        {
          "name": "FUNCTIONS_EXTENSION_VERSION",
          "value": "~3"
        },
        {
          "name": "AzureWebJobsSecretStorageType",
          "value": "files"
        },

Then you can get the url or the key and url using:

  "outputs": {
    "mValidateConfigurationUrl": {
      "type": "string",
      "value": "[listsecrets(resourceId('Microsoft.Web/sites/functions', variables('functionsName'), 'mValidateConfiguration'),'2015-08-01').trigger_url]"
    },
    "mValidateConfigurationUrlObj": {
      "type": "object",
      "value": "[listsecrets(resourceId('Microsoft.Web/sites/functions', variables('functionsName'), 'mValidateConfiguration'),'2015-08-01')]"
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM