How to pass Azure Function Keys to tests in a YAML pipeline

Laura Jaques
OS TechBlog
Published in
4 min readAug 26, 2021
A photograph of a small silver key on a white background
Vachette Radial NT key by D4m1en is licensed under Creative Commons 3.0

If you want to test your Function App in a CI/CD pipeline in Azure DevOps, you’ll need to get its access keys. Here’s how.

What are Access Keys?
Azure Functions come with built-in protection in the form of access keys. It’s one of the easiest ways to secure a Function App.

When you hit a function’s HTTP trigger, you must include an access key, or nothing will happen (unless you set the HTTP access level to ‘anonymous’ ).
You can find your keys in the Azure Portal: ‘host keys’ at the function app level, and ‘function keys’ at the function level. Host keys allow access to all functions within a function app. Function keys allow access to one specific function only.

A screenshot of the Microsoft Azure Portal showing the Host Keys of a function app.
Host Keys in the Microsoft Azure Portal
A screenshot of the Microsoft Azure Portal showing the Function Keys of a function app
Function Keys in the Microsoft Azure Portal

These access keys allow you to securely invoke your functions, and they also allow you to test them.

Why do I need to supply keys to my tests in the pipeline?
You won’t have the keys the first time you run your pipeline, because the function app they unlock doesn’t exist yet. After that, every time you tear down your app and redeploy it, or deploy your app to a new environment, the keys will change.

Even if you don’t mind loads of manual updating (which you almost definitely do), putting the keys directly into your test code isn’t secure.
So, you need a way to provide access keys to your tests within your deployment pipeline.

How do I pass my Function Keys to my tests?
An important thing to note here is that the tests that test your function app don’t run on the app service itself, they run on the build agent responsible for deploying it. So, you need to wait for the app deployment to finish, grab the keys, and make them available to the build agent before it gets to the tests.
It only takes five lines of PowerShell to retrieve a function key and make it available to a build agent.

1. Add an Azure CLI@2 Task to the pipeline.
We deploy our functions to Azure using pipelines in Azure DevOps. So, the first thing we need is an Azure CLI@2 Task. It needs to go before the tests and after the deployment of the Function App and the code. Give it the name of your service connection , set the scriptType to ‘pscore’, and choose ‘inline script’.

- task: AzureCLI@2
displayName: Title of some kind
inputs:
azureSubscription: $(ServiceConnectionName)
scriptType: ‘pscore’
scriptLocation: ‘inlineScript’
inlineScript:

2. Construct a function app resource ID.
Next, we need to construct the resource ID for the function app we’re interested in. To do this, we’ll need the 32-digit subscription id of the subscription the app lives in, the name of its resource group, and the name of the function app itself.

$ResourceId = “/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.Web/sites/$FunctionAppName

3. Retrieve the function keys using Az Rest.
Now, we’re ready to make the REST request for the access keys. To maintain isolation between different functions, we will be requesting the ‘function keys’ here. But you can also access the ‘host keys’ if you want to hit all the functions together.

To get the function keys, we’ll need the resource id we created in the previous step, and the name of the function itself. This is the name associated with the HTTP trigger in your source code. For example, in C#

[FunctionName(“MyFunctionName”)]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, “get”, “post”, Route = null)] HttpRequest req,
ILogger log)
{
}

We’ll add the following line to our inline script to retrieve the function keys using the $ResourceId we just generated, and we’ll pipe the JSON response into a PowerShell object.

$functionKeys = az rest — method post -o json — uri “https://management.azure.com$ResourceId/functions/$FunctionName/listKeys?api-version=2018-02-01" | ConvertFrom-Json

4. Extract the default key.
Now, we can extract the key we want to use to access the function. Microsoft provide you with one, named ‘default’, which is the one we will access here. You can, of course, name and set your own.

$FunctionKey = $functionKeys.default

5. Create the function URL.
Next, we construct the URL for the HTTP trigger. It has three parts that uniquely identify and unlock your function: the function app name, the function name, and the function key.

$FunctionUrl = “https://” + $FunctionAppName + “.azurewebsites.net/api/” + $FunctionName + “?code=” + $FunctionKey

6. Make the function URL available to the test.
The final step is to make the function URL available to the tests. To do this, we’ll use the task.setvariable command. This will assign the function URL to a new variable in your pipeline. That variable will be available to any downstream task in the same job.

We’ll set the flag ‘issecret’ to ‘true’ to make sure that our function key remains hidden from the logs.

Write-Host “##vso[task.setvariable variable=FunctionUrl;issecret=true]$FunctionUrl”

And that’s it. As long as your test task runs after this PowerShell task, and within the same job, it will have access to the function key.

Every time your pipeline runs, it will retrieve the latest version of that key and supply it to the tests. If you update the key, tear down and redeploy your function app, or roll out to a new environment, you won’t have to go back and update your tests. They’ll update automatically.

--

--