3

Summary: I'm authoring a function directly in Visual Studio which by design results in readonly function management in the portal. My question is how does one easily create a function key for said webhook?

Context: I'm trying to hook up a generic webhook to Event Grid. This process has led me down a path of needing to trigger a SubscriptionValidationEvent which in turn requires my webhook to provide a "code" on the URL which I'm assuming is a function key.

Also before I get down voted, I'm very well aware that there are multiple variants of this question asked and answered here already. I've tried them all and for one reason or another none of the solutions that involve writing PowerShell against a poorly documented Keys API using Kudu creds seem to work for me.

My hope is that someone knows of a way to solve this with the CLI or even easier, creating a functionName.json file by hand and dropping it in the secrets directory.

Lastly as tempting as it is for me to use the prerelease EventGrid binding, I'm currently unable to push pre-release code in my environment.

Thomas
  • 24,234
  • 6
  • 81
  • 125
ThatCreole
  • 495
  • 1
  • 7
  • 17
  • Do you need some sample code to generate key using the kudu api ? it is the only reliable option that I foudn and used in production so far. – Thomas May 09 '18 at 05:58
  • Is it an option for you to make the function `Read/Write` from the portal? You can do this from the Application Settings also https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings#functionappeditmode – Vladislav May 09 '18 at 07:21
  • @Thomas yes please. Though I've not gotten the powershell samples from here to work. – ThatCreole May 09 '18 at 13:02
  • @Vladislav I tried that too. When you do that the portal says "Your app is currently in read/write mode because you've set the edit mode to read/write despite having a generated function.json. Changes made to function.json will not be honored by the Functions runtime." – ThatCreole May 09 '18 at 13:03

1 Answers1

5

Found this interesting article on how to manage azure functions keys from Powershell:

Also official documentation (was hard to find this wiki):

Here are the key points:

  1. Get the publishing credentials
  2. Generate the Kudu API Authorisation token
  3. Call Kudu /api/functions/admin/token to get a JWT that can be used with the Functions Key API
  4. Then you can do whatever you want

Here is my existing script

    Param(
    [string] [Parameter(Mandatory=$true)] $resourceGroupName,
    [string] [Parameter(Mandatory=$true)] $functionappName,
    [string] [Parameter(Mandatory=$true)] $keyname,
    [string] [Parameter()] $slot
)

if (![string]::IsNullOrWhiteSpace($slot)){
    $apiBaseUrl = "https://$functionappName-$slot.scm.azurewebsites.net/api"
    $siteBaseUrl = "https://$functionappName-$slot.azurewebsites.net"
    $resourceType = "Microsoft.Web/sites/slots/config"
    $resourceName = "$functionappName/$slot/publishingcredentials"
}
else {
    $apiBaseUrl = "https://$functionappName.scm.azurewebsites.net/api"
    $siteBaseUrl = "https://$functionappName.azurewebsites.net"
    $resourceType = "Microsoft.Web/sites/config"
    $resourceName = "$functionappName/publishingcredentials"
}

Write-Host "Get the publishing credentials"
$publishingCredentials = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType $resourceType -ResourceName $resourceName -Action list -ApiVersion 2015-08-01 -Force

Write-Host "Generate the Kudu API Authorisation Token"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $publishingCredentials.Properties.PublishingUserName, $publishingCredentials.Properties.PublishingPassword)))

Write-Host "Call Kudu /api/functions/admin/token to get a JWT that can be used with the Functions Key API"
$jwt = Invoke-RestMethod -Uri "$apiBaseUrl/functions/admin/token" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET

Write-Host "Creates or updates an host key at the specified resource with an auto generated key"
$mynewkey = (Invoke-RestMethod -Uri "$siteBaseUrl/admin/host/keys/$keyname" -Headers @{Authorization=("Bearer {0}" -f $jwt)} -Method Post).value

EDIT

Newly created function apps use TLS 1.2 by default so you need to add this line at the top of the Powershell script:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • Thanks Thomas. So this has me super close. I ***think*** I'm getting caught up on the fact that I'm trying to run this against a deployment slot. I've modified the code above to make `$resourceType = "Microsoft.Web/sites/slots/config"` and `$resourceName = "$functionappName//publishingcredentials"`. This at least allows me to get a legit JWT. The POST to generate the new key at this location `$siteBaseUrl/admin/host/keys/$keyname` seems wrong though. I'm sure there's a slot path in there somewhere but it's non obvious. – ThatCreole May 10 '18 at 05:58
  • Yeah you may need to modify this location `$siteBaseUrl/admin/host/keys/$keyname` to include the slot. not really sure how to do this. will have a look now – Thomas May 10 '18 at 06:30
  • @ThatCreole, just tried just modifying the resourceType and the resourceName and I can see my new key on the portal – Thomas May 10 '18 at 06:50
  • Wait what paths did you use?! – ThatCreole May 10 '18 at 12:11
  • Sorry for my late answer, I've updated my script to deal with slot – Thomas May 11 '18 at 07:18
  • your our script and mine was basically the same but the last bit (POST to make the key) failed. After I debugged a bit turns out it was getting tripped up on the fact that I had EasyAuth enabled. Rather than spending time to figure out what other token I needed, I temporarily disabled auth, ran it, got the key, then enabled auth again. Ultimately it solved my problem though. Thank you! – ThatCreole May 11 '18 at 09:59