Quickstart: Create an ExpressRoute circuit with private peering using an ARM template

This quickstart describes how to use an Azure Resource Manager template (ARM template) to create an ExpressRoute circuit with private peering.

Diagram of ExpressRoute circuit deployment environment using ARM template.

An Azure Resource Manager template is a JavaScript Object Notation (JSON) file that defines the infrastructure and configuration for your project. The template uses declarative syntax. You describe your intended deployment without writing the sequence of programming commands to create the deployment.

If your environment meets the prerequisites and you're familiar with using ARM templates, select the Deploy to Azure button. The template opens in the Azure portal.

Button to deploy the Resource Manager template to Azure.

Prerequisites

If you don't have an Azure subscription, create a free account before you begin.

Review the template

The template used in this quickstart is from Azure Quickstart Templates.

In this quickstart, you create an ExpressRoute circuit with Equinix as the service provider. The circuit is using a Premium SKU, with a bandwidth of 50 Mbps, and the peering location of Washington DC. Private peering is enabled with a primary and secondary subnet of 192.168.10.16/30 and 192.168.10.20/30 respectively. A virtual network gets created along with a HighPerformance ExpressRoute gateway.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.26.170.59819",
      "templateHash": "1648633191574795729"
    }
  },
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources deployed in the Bicep file"
      }
    },
    "erpeeringLocation": {
      "type": "string",
      "defaultValue": "Washington DC",
      "metadata": {
        "description": "ExpressRoute peering location"
      }
    },
    "erCircuitName": {
      "type": "string",
      "defaultValue": "er-ckt01",
      "metadata": {
        "description": "Name of the ExpressRoute circuit"
      }
    },
    "serviceProviderName": {
      "type": "string",
      "defaultValue": "Equinix",
      "metadata": {
        "description": "Name of the ExpressRoute provider"
      }
    },
    "erSKU_Tier": {
      "type": "string",
      "defaultValue": "Premium",
      "allowedValues": [
        "Premium",
        "Standard"
      ],
      "metadata": {
        "description": "Tier ExpressRoute circuit"
      }
    },
    "erSKU_Family": {
      "type": "string",
      "defaultValue": "MeteredData",
      "allowedValues": [
        "MeteredData",
        "UnlimitedData"
      ],
      "metadata": {
        "description": "Billing model ExpressRoute circuit"
      }
    },
    "bandwidthInMbps": {
      "type": "int",
      "defaultValue": 50,
      "allowedValues": [
        50,
        100,
        200,
        500,
        1000,
        2000,
        5000,
        10000
      ],
      "metadata": {
        "description": "Bandwidth ExpressRoute circuit"
      }
    },
    "peerASN": {
      "type": "int",
      "defaultValue": 65001,
      "metadata": {
        "description": "autonomous system number used to create private peering between the customer edge router and MSEE routers"
      }
    },
    "primaryPeerAddressPrefix": {
      "type": "string",
      "defaultValue": "192.168.10.16/30",
      "metadata": {
        "description": "point-to-point network prefix of primary link between the customer edge router and MSEE router"
      }
    },
    "secondaryPeerAddressPrefix": {
      "type": "string",
      "defaultValue": "192.168.10.20/30",
      "metadata": {
        "description": "point-to-point network prefix of secondary link between the customer edge router and MSEE router"
      }
    },
    "vlanId": {
      "type": "int",
      "defaultValue": 100,
      "metadata": {
        "description": "VLAN Id used between the customer edge routers and MSEE routers. primary and secondary link have the same VLAN Id"
      }
    },
    "vnetName": {
      "type": "string",
      "defaultValue": "vnet1",
      "metadata": {
        "description": "name of the Virtual Network"
      }
    },
    "subnet1Name": {
      "type": "string",
      "defaultValue": "subnet1",
      "metadata": {
        "description": "name of the subnet"
      }
    },
    "vnetAddressSpace": {
      "type": "string",
      "defaultValue": "10.10.10.0/24",
      "metadata": {
        "description": "address space assigned to the Virtual Network"
      }
    },
    "subnet1Prefix": {
      "type": "string",
      "defaultValue": "10.10.10.0/25",
      "metadata": {
        "description": "network prefix assigned to the subnet"
      }
    },
    "gatewaySubnetPrefix": {
      "type": "string",
      "defaultValue": "10.10.10.224/27",
      "metadata": {
        "description": "network prefixes assigned to the gateway subnet. It has to be a network prefix with mask /27 or larger"
      }
    },
    "gatewayName": {
      "type": "string",
      "defaultValue": "er-gw",
      "metadata": {
        "description": "name of the ExpressRoute Gateway"
      }
    },
    "gatewaySku": {
      "type": "string",
      "defaultValue": "HighPerformance",
      "allowedValues": [
        "Standard",
        "HighPerformance",
        "UltraPerformance",
        "ErGw1AZ",
        "ErGw2AZ",
        "ErGw3AZ"
      ],
      "metadata": {
        "description": "ExpressRoute Gateway SKU"
      }
    }
  },
  "variables": {
    "erSKU_Name": "[format('{0}_{1}', parameters('erSKU_Tier'), parameters('erSKU_Family'))]",
    "gatewayPublicIPName": "[format('{0}-pubIP', parameters('gatewayName'))]",
    "nsgName": "nsg"
  },
  "resources": [
    {
      "type": "Microsoft.Network/expressRouteCircuits",
      "apiVersion": "2023-09-01",
      "name": "[parameters('erCircuitName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[variables('erSKU_Name')]",
        "tier": "[parameters('erSKU_Tier')]",
        "family": "[parameters('erSKU_Family')]"
      },
      "properties": {
        "serviceProviderProperties": {
          "serviceProviderName": "[parameters('serviceProviderName')]",
          "peeringLocation": "[parameters('erpeeringLocation')]",
          "bandwidthInMbps": "[parameters('bandwidthInMbps')]"
        },
        "allowClassicOperations": false
      }
    },
    {
      "type": "Microsoft.Network/expressRouteCircuits/peerings",
      "apiVersion": "2023-09-01",
      "name": "[format('{0}/{1}', parameters('erCircuitName'), 'AzurePrivatePeering')]",
      "properties": {
        "peeringType": "AzurePrivatePeering",
        "peerASN": "[parameters('peerASN')]",
        "primaryPeerAddressPrefix": "[parameters('primaryPeerAddressPrefix')]",
        "secondaryPeerAddressPrefix": "[parameters('secondaryPeerAddressPrefix')]",
        "vlanId": "[parameters('vlanId')]"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/expressRouteCircuits', parameters('erCircuitName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2023-09-01",
      "name": "[variables('nsgName')]",
      "location": "[parameters('location')]",
      "properties": {
        "securityRules": [
          {
            "name": "SSH-rule",
            "properties": {
              "description": "allow SSH",
              "protocol": "Tcp",
              "sourcePortRange": "*",
              "destinationPortRange": "22",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "VirtualNetwork",
              "access": "Allow",
              "priority": 500,
              "direction": "Inbound"
            }
          },
          {
            "name": "RDP-rule",
            "properties": {
              "description": "allow RDP",
              "protocol": "Tcp",
              "sourcePortRange": "*",
              "destinationPortRange": "3389",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "VirtualNetwork",
              "access": "Allow",
              "priority": 600,
              "direction": "Inbound"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2023-09-01",
      "name": "[parameters('vnetName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[parameters('vnetAddressSpace')]"
          ]
        },
        "subnets": [
          {
            "name": "[parameters('subnet1Name')]",
            "properties": {
              "addressPrefix": "[parameters('subnet1Prefix')]",
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]"
              }
            }
          },
          {
            "name": "GatewaySubnet",
            "properties": {
              "addressPrefix": "[parameters('gatewaySubnetPrefix')]"
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2023-09-01",
      "name": "[variables('gatewayPublicIPName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard",
        "tier": "Regional"
      },
      "properties": {
        "publicIPAllocationMethod": "Static"
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworkGateways",
      "apiVersion": "2023-09-01",
      "name": "[parameters('gatewayName')]",
      "location": "[parameters('location')]",
      "properties": {
        "ipConfigurations": [
          {
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), 'GatewaySubnet')]"
              },
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('gatewayPublicIPName'))]"
              }
            },
            "name": "gwIPconf"
          }
        ],
        "gatewayType": "ExpressRoute",
        "sku": {
          "name": "[parameters('gatewaySku')]",
          "tier": "[parameters('gatewaySku')]"
        },
        "vpnType": "RouteBased"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('gatewayPublicIPName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
      ]
    }
  ],
  "outputs": {
    "erCircuitName": {
      "type": "string",
      "value": "[parameters('erCircuitName')]"
    },
    "gatewayName": {
      "type": "string",
      "value": "[parameters('gatewayName')]"
    },
    "gatewaySku": {
      "type": "string",
      "value": "[parameters('gatewaySku')]"
    }
  }
}

Multiple Azure resources have been defined in the template:

To find more templates that are related to ExpressRoute, see Azure Quickstart Templates.

Deploy the template

  1. Select Try it from the following code block to open Azure Cloud Shell, and then follow the instructions to sign in to Azure.

    $projectName = Read-Host -Prompt "Enter a project name that is used for generating resource names"
    $location = Read-Host -Prompt "Enter the location (i.e. centralus)"
    $templateUri = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.network/expressroute-private-peering-vnet/azuredeploy.json"
    
    $resourceGroupName = "${projectName}rg"
    
    New-AzResourceGroup -Name $resourceGroupName -Location "$location"
    New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateUri $templateUri
    
    Read-Host -Prompt "Press [ENTER] to continue ..."
    

    Wait until you see the prompt from the console.

  2. Select Copy from the previous code block to copy the PowerShell script.

  3. Right-click the shell console pane and then select Paste.

  4. Enter the values.

    The resource group name is the project name with rg appended.

    It takes about 20 minutes to deploy the template. When completed, the output is similar to:

    ExpressRoute Resource Manager template PowerShell deployment output

Azure PowerShell is used to deploy the template. In addition to Azure PowerShell, you can also use the Azure portal, Azure CLI, and REST API. To learn other deployment methods, see Deploy templates.

Validate the deployment

  1. Sign in to the Azure portal.

  2. Select Resource groups from the left pane.

  3. Select the resource group that you created in the previous section. The default resource group name is the project name with rg appended.

  4. The resource group should contain the following resources seen here:

    ExpressRoute deployment resource group

  5. Select the ExpressRoute circuit er-ck01 to verify that the circuit status is Enabled, provider status is Not provisioned and private peering has the status of Provisioned.

    ExpressRoute deployment circuit

Note

You will need to call the provider to complete the provisioning process before you can link the virtual network to the circuit.

Clean up resources

When you no longer need the resources that you created with the ExpressRoute circuit, delete the resource group to remove the ExpressRoute circuit and all the related resources.

To delete the resource group, call the Remove-AzResourceGroup cmdlet:

Remove-AzResourceGroup -Name <your resource group name>

Next steps

In this quickstart, you created a:

  • ExpressRoute circuit
  • Virtual Network
  • VPN Gateway
  • Public IP
  • network security groups

To learn how to link a virtual network to a circuit, continue to the ExpressRoute tutorials.