For this post, I want to look at the connection you can make between GitHub and Azure Functions. I have written an extensive blog post about this subject before, which I encourage you to read if you have never created this connection before. I want to focus on how you can create a secure GitHub webhook to trigger an Azure PowerShell Function. We will make use of a secret that we will store in Azure Key vault.
As I have mentioned in the previous post, a webhook can be very handy to make some sort of action happen when an event occurs in your GitHub repository.
If you followed my previous blogpost, you will have noticed that you paste the URL of your function, including the key, into the Payload URL field in the webhook. While this is ok, it does mean that the key is retrievable in the webhooks header. If your URL is compromised, anyone is able to trigger your Function App.
To prevent that, you can add a secret to the webhook. If you check that secret within the function app, you can verify that the URL has been called by the specific webhook you have set up.
For this post, I assume you already know how to create an Azure Function App and how to create a GitHub webhook. For some guidance, you can view the following links:
- Create a PowerShell Function App in the portal
- Create a PowerShell function in Azure using Visual Studio Code
- Trigger an Azure Function app with a GitHub webhook
To start this post, make sure you have the following:
- An Azure PowerShell Function.
- A GitHub repository. This can be a private or public one. We will create the webhook in this guide.
- An Azure key vault. To know how to create one, click this doc.
How does it work
We are going to make use of the Secret in the GitHub webhook.
When the webhook creates a header and body to trigger the function app, it will add a hash that is based on a combination of your secret and the body of the request.
By creating that same hash in your script, you can compare the two and verify that the request was send by the Webhook.
You can find more details here.
Create a secure webhook
Let’s create the webhook. First, copy the URL of your Function app.
Open your GitHub repository and click settings. Select WebHooks
Click Add webhook. You might have to confirm your password.
In the URL field, paste the URL of your function app.
Set the content type to Application/json
For the Secret, enter the secret that you are going to use. This is best to be a generated secret of at least 24 characters. You can have one generated by most password tools, or use this PowerShell script.
Note: This script is part of a GitHub action, so the output is a bit different than expected. You can copy only the password, the part behind the “::“. If you want to know more about the action, click here.
Paste the password in the Secret field.
Change the trigger if needed and click add webhook.
You are done in GitHub now, let’s move on to Azure.
Store the secret in Key Vault
Although we could store the secret plain text in the script or save it in an app setting, the best way to store it in an Azure Key Vault and then give the Function access to it. If you are already familiar with this process or choose to save it in an app setting, you can move on to the next step by clicking here.
Open your key vault in the portal, click Secrets and then Generate/Import.
Give the secret a name and paste the secret you used before in the Value field. Save the secret.
Give the Function access to the Key Vault
We’ll move around a few time between the Function and the Key vault for this step.
Your function needs to be able to access this secret. The first thing we need to do, is assign the Function a managed identity. That way we can give it permissions to read the secret.
Read more about managed identities in Azure Functions here.
First open your function and select Identity in the menu.
In the new screen, set the switch to On, click Save and then yes.
Note: You need at least the application administrator role to do this action.
When it is done, go back to the key vault and click Access Policies.
Click + Add Access Policy.
The function needs to be able to get and list the secret. Select those options in the drop down menu.
Now click None Selected after Select principal.
You can find the function under its own name in the list. Click Select at the bottom of the screen and then Add.
Don’t forget to hit Save in the next screen, otherwise your new setting won’t be saved.
Add the secret to the Application settings
Move back to the secret in Key Vault. Click on the string for the current version.
Here you can find an URL: the secret identifier. Copy this URL.
Open up your function and click Configuration in the menu
Click + New application setting.
Create a new setting with the name WebhookSecret (or something else if it is more fitting for you). What you are creating here is an environment variable you can use in the script.
For the value, use the following format: @Microsoft.KeyVault(SecretUri=[keyvaulturl])
Check the secret in the function
Now we have the secret set in the webhook and securely available in our script, we need to actually check the secret in the script.
In the script, we will create the same hash as the webhook had created. We will then compare the two. If they are not the same, we will stop the script from performing an action. This can be done in a simple if-else loop.
This is the code you can use around your function:
You can paste this code into your function and save/deploy it.
Now if you change a file in the GitHub repository, you will find that the secret was checked and found correct.
But if I try to call the URL without having the correct secret, it will give an error.
This is how you create a secure GitHub webhook to trigger an Azure PowerShell Function. If you have any questions or comments, leave them below!
How secure is the secret stored in GitHub? Presumably if this leaks then it would be possible le to invoke the Azure function.
If you are able to see the webhook of a repository, you are able to see the secret. As far as I can tell this permission is limited to the repository owner, if we are talking private repositories. For an organization I haven’t checked it yet. But it is a good thing to be careful with the permissions to be on the save side.
Pingback:Top Stories from the Microsoft DevOps Community – 2021.04.09 | Azure DevOps Blog
Pingback:Top Stories from the Microsoft DevOps Community – 2021.04.09 - Power Community
Pingback:Top Stories from the Microsoft DevOps Community – 2021.04.09 - Microsoft Today