Harness and Azure Functions

Hey all!

This post is another in the Custom Deployer series, specifically with Azure functions. Here is the git repository with all of the scripts.

To bring this integration in, there are some pre-requisites on the Azure side before this can happen. First, you will need to have an Azure Service Principal to leverage the AZ CLI. This doc shows how to get the Service Principal set up. Using the AZ CLI to set up the Service Principal is the easiest way that I’ve found. The output from creating the Service Principal will give you a response containing some required information to leverage in Harness: appId, tenant, and password.

Another Azure pre-requisite is that a Function App must be created for the Function to live in. The Azure Documentation has some good walk throughs on how to get the Function App setup.

The last pre-requisite is related to the artifact type for the function. Azure allows you to deploy a ZIP file or the contents of a Git repository to an Azure Function. The Git repository must be available via HTTPS, whether that is public or private. This doc will show how to deploy both a Git-based Azure Function and a ZIP based Azure Function. If your Git repository requires authentication, you will need to add --private-repo-password and --private-repo-username to the Git command in this post. The secret and/or the username can be added the Harness Secrets Manager to keep it secret.

Once you have that information, you need to create 2 secrets in the Harness Secrets Manager using the Password from the Create Service Principal response mentioned above (Note: Please do not use the - character in your naming convention):

  1. The first secret will be applied to the Delegate. As a result, I named the secret β€œazure_sp_del” and the Scope to Account checkbox MUST BE CHECKED:

  2. The second secret will be applied in different commands. As a result, I named the secret β€œazure_sp” and the Scope to Account checkbox MUST NOT BE CHECKED, but you can scope the secret to specific Applications at the bottom, if necessary:

Delegate Profile
Next, you will need to setup a Delegate Profile using the App ID and Tenant ID from the Service Principal Create output:

  1. Setup > Harness Delegates > Delegate Profiles:
    # Adding Python PIP
    echo β€œ β€œ && echo "apt-get update" && echo β€œ β€œ
    apt-get update
    echo β€œ β€œ && echo "install pip" && echo β€œ β€œ
    apt-get -y install python3-pip
    echo β€œ β€œ && echo "check pip version" && echo β€œ β€œ
    pip3 --version
    # Adding AZ-CLI
    echo β€œ β€œ && echo "install azure cli" && echo β€œ β€œ
    pip3 install azure-cli
    echo β€œ β€œ && echo "check azure version" && echo β€œ β€œ
    az --version
    # Add Login info
    az login --service-principal --username <APP ID> --password ${secrets.getValue("azure_sp_del")} --tenant <TENANT ID>

  2. Assign the Delegate Profile to a Delegate and add a Custom Selector called az-functions.

Harness Application Setup
This post will assume that you are using a Linux-based Azure Function. As such, we will not be going through slot deployments since that is not currently available with Linux-based Azure Functions.

There are three ways that the Azure Function App and Azure Function can be set up:

  1. Azure Function App and Azure Function have the same name
  2. Azure Function App and Azure Function have different names (multiple Functions per Function App)
  3. Azure Function App or Azure Function have an Environment-based naming convention (function-dev/function-prod or functionapp-dev/functionapp-prod)

If your current Azure Function setup is similar to number 1 above, then the Harness Service can be named after the Azure Function you are deploying.

If your current Azure Function setup is similar to number 2 or 3 above, which the examples in this post will be like number 2 above, then the Harness Application or Environment can be named after the Azure FunctionApp and the Harness Service can be named after the Azure Function you are deploying.

Custom Deployer

  1. To create the Custom Deployer, go to Setup > Template Library > + Add Template > Custom Deployment Type
  2. Add RES_GROUP and FUNC_APP as Infrastructure Variables
  3. Fetch Instance script
  4. Put a $ in the Host Object Array Path
  5. For the Host Attributes section, add the following setup:
    hostname = name
    Language = language
    ID = id
    URL = invokeUrlTemplate
    Location = location

Service Command Templates
This example will show how to pull a ZIP file from one artifact source and then upload it to Azure Functions

  1. Setup > Template Library > + Add Template > Service Command > Name the service command
  2. Click the + icon and add an Exec command
  3. Use this script. This script is using an AWS S3 bucket to pull the artifact. But if the artifact repository is different, please alter the script as needed.
  4. Click the + icon again and add another Exec command
  5. Use this script


  1. Setup > Template Library > + Add Template > Service Command > Name the service command and add two variables: GIT_URL and BRANCH
  2. Click the + icon and add an Exec command
  3. Use this script. This script uses a public Git repository, but if you need to use a private Git repository, then follow the alteration instructions at the top of this post.

Harness Service

  1. Application > Services > + Add Service > Name = Function Name (Case-sensitive) > Deployment Type = Name of the Custom Deployer > Artifact Type = ZIP File
  2. If you are using a ZIP file artifact then add an Artifact Source to point to the correct ZIP file
    . If you are not using a ZIP file, then you can leave that blank.

Harness Environment and Infrastructure Definition
The name of the Environment is important if your Azure Functions setup requires different environments to deploy to. If this is the case, please use a good naming convention for the Environment names so that you can leverage the built-in variables. For example, if your Azure Function requires a -dev or -qa for the FunctionApp name, then naming the Environment dev or qa will allow you to use ${env.name} to the end of the Function App name to make it easier for scaling (i.e. ${service.name}-${env.name} will always evaluate to what you need if you use the right naming convention). In this example, we are just using a generic Environment name.

To create the Infrastructure Definition:

  1. Environments > Desired Environment > + Add Infrastructure Definition > Name the Infrastructure Definition something recognizable (the example is azure-functions) > Cloud Provider Type = Custom > Deployment Type = Name of the Custom Deployer > Select Version = Latest > Add the Resource Group and the Function App name in the correct fields

Harness Workflow
I highly recommend using a Multi-Service Workflow for this process.

  1. Setup > Application > Workflows > + Add Workflow > Name = azure-functions > Workflow Type = Multi-Service Workflow > Environment = The environment you created above
  2. Deployment Phases > + Add Phase > Service = Custom Deployer Service > Infrastructure Definition = Infrastructure Definition created in the Environment
  3. Deploy > + Add Step > Template Library > Link the Service Command for either ZIP artifact or Git repository

  4. Move the deployment command before the Fetch Instance command
    a. If using the Git Service Command, make sure to add the Git Repo URL and Branch to the bottom
  5. Deploy the workflow
    Git Artifact

    ZIP Artifact

Hope this helps!

Don’t forget to Like/Comment/Share!

1 Like