Deploy an Azure API Management gateway on AKS using an ARM Template

The following Jumpstart scenario will guide you on how to deploy a “Ready to Go” environment so you can start using a self-hosted Azure API Management Gateway deployed on an Azure Kubernetes Service (AKS) cluster that has been onboarded as an Azure Arc-enabled Kubernetes cluster using an Azure ARM Template.

By the end of this scenario, you will have an AKS cluster deployed with an Azure API Management gateway, a backend API and a Microsoft Windows Server 2022 (Datacenter) Azure VM, installed & pre-configured with all the required tools needed to work with the Azure API Management gateway.

NOTE: Currently, API Management self-hosted gateway on Azure Arc is in preview. The deployment time for this scenario can take ~60-90 minutes


  • Clone the Azure Arc Jumpstart repository

    git clone
  • Install or update Azure CLI to version 2.42.0 and above. Use the below command to check your current installed version.

    az --version
  • Generate a new SSH key pair or use an existing one (Windows 10 and above now comes with a built-in ssh client).

    ssh-keygen -t rsa -b 4096

    To retrieve the SSH public key after it’s been created, depending on your environment, use one of the below methods:

    • In Linux, use the cat ~/.ssh/ command.
    • In Windows (CMD/PowerShell), use the SSH public key file that by default, is located in the C:\Users\WINUSER/.ssh/ folder.

    SSH public key example output:

    ssh-rsa o1djFhyNe5NXyYk7XVF7wOBAAABgQDO/QPJ6IZHujkGRhiI+6s1ngK8V4OK+iBAa15GRQqd7scWgQ1RUSFAAKUxHn2TJPx/Z/IU60aUVmAq/OV9w0RMrZhQkGQz8CHRXc28S156VMPxjk/gRtrVZXfoXMr86W1nRnyZdVwojy2++sqZeP/2c5GoeRbv06NfmHTHYKyXdn0lPALC6i3OLilFEnm46Wo+azmxDuxwi66RNr9iBi6WdIn/zv7tdeE34VAutmsgPMpynt1+vCgChbdZR7uxwi66RNr9iPdMR7gjx3W7dikQEo1djFhyNe5rrejrgjerggjkXyYk7XVF7wOk0t8KYdXvLlIyYyUCk1cOD2P48ArqgfRxPIwepgW78znYuwiEDss6g0qrFKBcl8vtiJE5Vog/EIZP04XpmaVKmAWNCCGFJereRKNFIl7QfSj3ZLT2ZXkXaoLoaMhA71ko6bKBuSq0G5YaMq3stCfyVVSlHs7nzhYsX6aDU6LwM/BTO1c= user@pc
  • Create Azure service principal (SP). To deploy this scenario, an Azure service principal assigned with multiple Role-based access control (RBAC) roles is required:

    • “Contributor” - Required for provisioning Azure resources

    • “Security admin” - Required for installing Cloud Defender Azure-Arc enabled Kubernetes extension and dismiss alerts

    • “Security reader” - Required for being able to view Azure-Arc enabled Kubernetes Cloud Defender extension findings

      To create it login to your Azure account run the below command (this can also be done in Azure Cloud Shell.

      az login
      subscriptionId=$(az account show --query id --output tsv)
      az ad sp create-for-rbac -n "<Unique SP Name>" --role "Contributor" --scopes /subscriptions/$subscriptionId
      az ad sp create-for-rbac -n "<Unique SP Name>" --role "Security admin" --scopes /subscriptions/$subscriptionId
      az ad sp create-for-rbac -n "<Unique SP Name>" --role "Security reader" --scopes /subscriptions/$subscriptionId

      For example:

      az login
      subscriptionId=$(az account show --query id --output tsv)
      az ad sp create-for-rbac -n "JumpstartArcAppSvc" --role "Contributor" --scopes /subscriptions/$subscriptionId
      az ad sp create-for-rbac -n "JumpstartArcAppSvc" --role "Security admin" --scopes /subscriptions/$subscriptionId
      az ad sp create-for-rbac -n "JumpstartArcAppSvc" --role "Security reader" --scopes /subscriptions/$subscriptionId

      Output should look like this:

      "displayName": "JumpstartArcAppSvc",

      NOTE: If you create multiple subsequent role assignments on the same service principal, your client secret (password) will be destroyed and recreated each time. Therefore, make sure you grab the correct password.

      NOTE: The Jumpstart scenarios are designed with as much ease of use in-mind and adhering to security-related best practices whenever possible. It is optional but highly recommended to scope the service principal to a specific Azure subscription and resource group as well considering using a less privileged service principal account

Automation Flow

For you to get familiar with the automation and deployment flow, below is an explanation.

  • User is editing the ARM template parameters file (1-time edit). These parameters values are being used throughout the deployment.

  • Main azuredeploy ARM template will initiate the deployment of the linked ARM templates:

    • clientVm - Deploys the client Windows VM. This is where all user interactions with the environment are made from.
    • logAnalytics - Deploys Azure Log Analytics workspace to support Azure API Management logs uploads.
  • User remotes into client Windows VM, which automatically kicks off the AppServicesLogonScript PowerShell script that deploy the AKS cluster and will configureAzure Arc-enabled app services Kubernetes environment on the AKS cluster.

    NOTE: Notice the AKS cluster will be deployed via the PowerShell script automation.


NOTE: The deployment time for this scenario can take ~60-90 minutes

As mentioned, this deployment will leverage ARM templates. You will deploy a single template that will initiate the entire automation for this scenario.

  • The deployment is using the ARM template parameters file. Before initiating the deployment, edit the azuredeploy.parameters.json file located in your local cloned repository folder. An example parameters file is located here.

    • sshRSAPublicKey - Your SSH public key
    • spnClientId - Your Azure service principal id
    • spnClientSecret - Your Azure service principal secret
    • spnTenantId - Your Azure tenant id
    • windowsAdminUsername - Client Windows VM Administrator name
    • windowsAdminPassword - Client Windows VM Password. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. The value must be between 12 and 123 characters long.
    • logAnalyticsWorkspaceName - Unique name for the deployment log analytics workspace.
    • kubernetesVersion - AKS version
    • dnsPrefix - AKS unique DNS prefix
    • deployAppService Boolean that sets whether or not to deploy App Service plan and a Web App. For this scenario, we leave it set to false.
    • deployFunction - Boolean that sets whether or not to deploy App Service plan and an Azure Function application. For this scenario, we leave it set to false.
      • deployLogicApp - Boolean that sets whether or not to deploy App Service plan and an Azure Logic App. For this scenario, we leave it set to false.
    • deployAPIMgmt - Boolean that sets whether or not to deploy a self-hosted Azure API Management gateway. For this scenario, we leave it set to true.
    • templateBaseUrl - GitHub URL to the deployment template - filled in by default to point to Microsoft/Azure Arc repository, but you can point this to your forked repo as well.
    • adminEmail - an email address that will be used on the Azure API Management deployment to receive all system notifications.
    • deployBastion - Choice (true | false) to deploy Azure Bastion or not to connect to the client VM.
    • bastionHostName - Azure Bastion host name.
  • To deploy the ARM template, navigate to the local cloned deployment folder and run the below command:

    az group create --name <Name of the Azure resource group> --location <Azure Region>
    az deployment group create \
    --resource-group <Name of the Azure resource group> \
    --name <The name of this deployment> \
    --template-uri \
    --parameters <The *azuredeploy.parameters.json- parameters file location>

    NOTE: Make sure that you are using the same Azure resource group name as the one you’ve just used in the azuredeploy.parameters.json file

    For example:

    az group create --name Arc-API-Demo --location "East US"
    az deployment group create \
    --resource-group Arc-API-Demo \
    --name arcappsvc \
    --template-uri \
    --parameters azuredeploy.parameters.json
  • Once Azure resources has been provisioned, you will be able to see it in Azure portal. At this point, the resource group should have 7 various Azure resources deployed.

    ARM template deployment completed

    New Azure resource group with all resources

Windows Login & Post Deployment

Various options are available to connect to Arc-App-Client VM, depending on the parameters you supplied during deployment.

  • RDP - available after configuring access to port 3389 on the Arc-App-Client-NSG, or by enabling Just-in-Time access (JIT).
  • Azure Bastion - available if true was the value of your deployBastion parameter during deployment.

Connecting directly with RDP

By design, port 3389 is not allowed on the network security group. Therefore, you must create an NSG rule to allow inbound 3389.

  • Open the Arc-App-Client-NSG resource in Azure portal and click “Add” to add a new rule.

    Screenshot showing Arc-App-Client NSG with blocked RDP

    Screenshot showing adding a new inbound security rule

  • Specify the IP address that you will be connecting from and select RDP as the service with “Allow” set as the action. You can retrieve your public IP address by accessing or

    Screenshot showing all inbound security rule

    Screenshot showing all NSG rules after opening RDP

    Screenshot showing connecting to the VM using RDP

Connect using Azure Bastion

  • If you have chosen to deploy Azure Bastion in your deployment, use it to connect to the VM.

    Screenshot showing connecting to the VM using Bastion

    NOTE: When using Azure Bastion, the desktop background image is not visible. Therefore some screenshots in this guide may not exactly match your experience if you are connecting with Azure Bastion.

Connect using just-in-time access (JIT)

If you already have Microsoft Defender for Cloud enabled on your subscription and would like to use JIT to access the Client VM, use the following steps:

  • In the Client VM configuration pane, enable just-in-time. This will enable the default settings.

    Screenshot showing the Microsoft Defender for cloud portal, allowing RDP on the client VM

    Screenshot showing connecting to the VM using JIT

Post Deployment

  • At first login, as mentioned in the “Automation Flow” section above, the AppServicesLogonScript PowerShell logon script will start it’s run.

  • Let the script to run its course and do not close the PowerShell session, this will be done for you once completed. Once the script will finish it’s run, the logon script PowerShell session will be closed, the Windows wallpaper will change and the Azure web application will be deployed on the cluster and be ready to use.

    NOTE: As you will notices from the screenshots below, during the Azure Arc-enabled app services environment, the log-processor service pods will be restarted and will go through multiple Kubernetes pod lifecycle stages. This is normal and can safely be ignored. To learn more about the various Azure Arc-enabled app services Kubernetes components, visit the official Azure Docs page.

    PowerShell logon script run

    PowerShell logon script run

    PowerShell logon script run

    PowerShell logon script run

    PowerShell logon script run

    PowerShell logon script run

    Once the script finishes it’s run, the logon script PowerShell session will be closed, the Windows wallpaper will change, and both the API Management gateway and the sample API will be configured on the cluster.

    Wallpaper change

  • There will be newly deployed Azure resources in the resources group. The important ones to notice are:

    • Azure Arc-enabled Kubernetes cluster - Azure Arc-enabled app services are using this resource to deploy the app services cluster extension, as well as using Azure Arc Custom locations.

    • Custom location - Provides a way for tenant administrators to use their Azure Arc-enabled Kubernetes clusters as a target location for deploying Azure services.

    • App Service Kubernetes Environment - The App Service Kubernetes environment resource is required before apps may be created. It enables configuration common to apps in the custom location, such as the default DNS suffix.

    • App Service plan - In App Service (Web Apps, API Apps, or Mobile Apps), an app always runs in an App Service plan. In addition, Azure Functions also has the option of running in an App Service plan. An App Service plan defines a set of compute resources for a web app to run.

    • App Service - Azure App Service is an HTTP-based service for hosting web applications, REST APIs, and mobile back ends.

    Additional Azure resources in the resource group

API Management self-hosted gateway

In this scenario, the Azure Arc-enabled API Management cluster extension was deployed and used throughout this scenario in order to deploy the self-hosted API Management gateway services infrastructure.

  • In order to view cluster extensions, click on theAzure Arc-enabled Kubernetes resource Extensions settings.

    Azure Arc-enabled Kubernetes resource

    Azure Arc-enabled Kubernetes cluster extensions settings

Deploying the API Management gateway extension to an Azure Arc-enabled Kubernetes cluster creates an Azure API Management self-hosted gateway. You can verify this from the portal by going to the Resource Group and selecting the API management service.

API management service

Select Gateways on the Deployment + infrastructure section.

Self-hosted Gateway

A self-hosted gateway should be deployed with one connected node.

Connected node on self-hosted gateway

In this scenario, a sample Demo conference API was deployed. To view the deployed API, simply click on the self-hosted gateway resource and select on APIs.

Demo Conference API

To demonstrate that the self-hosted gateway is processing API requests you need to identify two elements:

  • Public IP address of the self-hosted gateway, by running the command below from the client VM.

    kubectl get svc -n apimgmt

    Self-hosted gateway public IP

  • API management subscription key, from the Azure portal on the API Management service resource select Subscriptions under APIs and select Show/hide keys for the one with display name “Built-in all-access subscription”.

    Self-hosted gateway subscriptions

    Subscription key

Once you have obtained these two parameters, replace them on the following code snippet and run it from the client VM PowerShell.

  $publicip = <self hosted gateway public IP>
  $subscription = <self hosted gateway subscription>
  $url = "http://$($publicip):5000/conference/topics"
  $headers = @{
  'Ocp-Apim-Subscription-Key' = $subscription
  'Ocp-Apim-Trace' = 'true'
  While ($i -le 10)
  Invoke-RestMethod -URI $url -Headers $headers

API calls test

In the Overview page of the API Management service, you can now see how the self-hosted gateway API requests are now shown.

API requests metrics


  • If you want to delete the entire environment, simply delete the deployed resource group from the Azure portal.

    Delete Azure resource group