This is part 2.5 of a promised two-part series on creating Azure virtual networks using Azure Resource Manger templates. The ARM template below is an example that will create a peer between any two networks in any two subscriptions. In other words, you do not have to run the deployment in a subscription that contains a virtual network that is one end of the peering relationship.
The “half-part” is because between the first part — which offers a sample that creates Vnets in an arbitrary number of subscriptions — and this post I “detoured” to show how it could be done better, IMHO, in PowerShell.
Update 2019-08-03: Here are links to the other posts in this series:
An example template to create an Azure Vnet
Create user-defined routes and associate them with subnets using ARM
Sample ARM templates to create network security groups and attach them to Vnets
Having made the case, at least as far as I am concerned, that PowerShell doesn’t deserve the reputation it’s gotten as a second-class deployment tool for cloud environments, I returned to the task at hand: using ARM templates to peer any two existing virtual networks.
I’ve complained previously about the fact that Azure Resource Manager templates presume that resources are to be created or modified in the subscription and resource group in which the deployment is running. That makes it a very unnatural act to “switch” to a different subscription/resource group. You have to use a nested template within another resource to be able to switch to different subs and/or RGs.
The template below uses nested templates twice, via two separate Microsoft.Resources/deployments
to deploy virtual network peering from Vnet A to Vnet B and then again from Vnet B to Vnet A.
But that’s not the most interesting part of the template for peering Azure virtual networks. In the nested template’s resource section for the type Microsoft.Networks/virtualNetworks/virtualNetworkPeerings
you’ll see a name constructed like this: [concat(parameters('ParameterArray')[copyIndex()].VnetBName, '/Peered-to-', parameters('ParameterArray')[copyIndex()].VnetAName)]
.
This turned out to be key to getting the template to run correctly. It turns out that the name must be precisely one level deeper than the resource type. The documentation for virtualNetworkPeerings
tells you a name is required but fails to tell you how to contstruct one properly when this type is used separately from virtualNetworks
. So, if you’ve found this blog post because you were getting name errors at template deployment time, now you know.
Here’s the template file, followed by the parameter file. Both are (c) 2018 Air11 Technology LLC and are licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0
{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "parameters": { "ParameterArray": { "type": "array" } }, "variables": {}, "resources": [ { "apiVersion": "2017-05-10", "name": "[concat('Peer-',parameters('ParameterArray')[copyIndex()].VnetAName, '-to-', parameters('ParameterArray')[copyIndex()].VnetBName)]", "type": "Microsoft.Resources/deployments", "subscriptionId": "[parameters('ParameterArray')[copyIndex('Vnets')].VnetASubscriptionId]", "resourceGroup": "[parameters('ParameterArray')[copyIndex('Vnets')].VnetAResourceGroup]", "copy": { "name": "Vnets", "count": "[length(parameters('ParameterArray'))]" }, "properties": { "mode": "Incremental", "template": { "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "variables": {}, "resources": [ { "apiVersion": "2017-10-01", "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", "name": "[concat(parameters('ParameterArray')[copyIndex()].VnetAName, '/Peered-to-', parameters('ParameterArray')[copyIndex()].VnetBName)]", "location": "[parameters('ParameterArray')[copyIndex()].VnetAResourceGroup]", "properties": { "allowVirtualNetworkAccess": true, "allowForwardedTraffic": false, "allowGatewayTransit": false, "useRemoteGateways": false, "remoteVirtualNetwork": { "id": "[resourceId(parameters('ParameterArray')[copyIndex()].VnetBSubscriptionID, parameters('ParameterArray')[copyIndex()].VnetBResourceGroup,'Microsoft.Network/virtualNetworks', parameters ('ParameterArray')[copyIndex()].VnetBName)]" } } } ] } } }, { "apiVersion": "2017-05-10", "name": "[concat('Peer-',parameters('ParameterArray')[copyIndex()].VnetBName, '-to-', parameters('ParameterArray')[copyIndex()].VnetAName)]", "type": "Microsoft.Resources/deployments", "resourceGroup": "[parameters('ParameterArray')[copyIndex()].VnetBResourceGroup]", "subscriptionId": "[parameters('ParameterArray')[copyIndex()].VnetBSubscriptionId]", "copy": { "name": "Vnets", "count": "[length(parameters('ParameterArray'))]" }, "properties": { "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "variables": {}, "resources": [ { "apiVersion": "2017-10-01", "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", "name": "[concat(parameters('ParameterArray')[copyIndex()].VnetBName, '/Peered-to-', parameters('ParameterArray')[copyIndex()].VnetAName)]", "location": "[parameters('ParameterArray')[copyIndex()].VnetBResourceGroup]", "properties": { "allowVirtualNetworkAccess": true, "allowForwardedTraffic": false, "allowGatewayTransit": false, "useRemoteGateways": false, "remoteVirtualNetwork": { "id": "[resourceId(parameters('ParameterArray')[copyIndex()].VnetASubscriptionId, parameters('ParameterArray')[copyIndex()].VnetAResourceGroup,'Microsoft.Network/virtualNetworks', parameters ('ParameterArray')[copyIndex()].VnetAName)]" } } } ] } } } ], "outputs": { } }
{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "0.0.0.1", "parameters": { "ParameterArray": { "value": [ { "VnetAName": "VnetA", "VnetBName": "VnetB", "VnetASubscriptionId": "f8777355-9999-7777-4444-123456fb271e", "VnetBSubscriptionId": "4f114590-9999-5556-ccec-b271e123456", "VnetAResourceGroup": "RgA", "VnetBResourceGroup": "RgB" }, { "VnetAName": "VnetA", "VnetCName": "VnetC", "VnetASubscriptionId": "f8777355-9999-7777-4444-123456fb271e", "VnetCSubscriptionId": "5f56ddd7-9999-5556-ccec-b271e123456", "VnetAResourceGroup": "RgA", "VnetCResourceGroup": "RgC" } ] } } }
Leave a Reply