How to create Azure virtual networks

This post offers a sample ARM template for creating Azure virtual networks (Vnets), with accompanying subnets. What’s different about this example is that it permits the creation of Azure Vnets in multiple subscriptions and resource groups. It’s part one of a two-part sample. The second part demonstrates how to peer Vnets that may be in different subscriptions. I’ll be posting that sample in a couple of weeks.

<rant>

Today, most cloud architects have adopted wholesale the DevOps shibboleth that declarative languages (e.g. JSON or YAML) are “better” for deploying cloud assets than procedural languages (e.g. PowerShell or bash). I may be alone on this, but I don’t agree. Consider the complexity it takes in a declarative language like JSON to do something simple like loop through an array of to-be-created virtual networks versus a foreach loop in PowerShell. The benefits of declarative approaches, which boil down to idempotency, pale next to the functionality, clarity and maintainability of scripting languages.

Update 2018-07-16: for a PowerShell alternative to this ARM template, see this post.

</rant>

In Azure Resource Manager (ARM) templates, you typically deploy to a single resource group in a single subscription. But what if you want to deploy virtual networks to different resource groups in different subscriptions? It can be done, but it requires using an Azure resource of type Microsoft.Resources/deployments. This resource allows specification of both a resourceGroupname and a subscriptionId name in the deployments object. The values for these names can, of course, come from a parameter.

Update 2019-03-18: Here are links to the other posts in this series:
A sample ARM template to peer Vnets
Create user-defined routes and associate them with subnets using ARM
Sample ARM templates to create network security groups and attach them to Vnets

A nested template can be the resource that’s deployed by type deployments . In this example, we use the fact that the nested template refers to a different different subscription and resource group than specified at deployment time to deploy resources in locations other than those supplied when the template is submitted to ARM.

So, how do we allow for multiple Vnets in a single deployment? A resource-level copy function is used to “loop” through the multiple virtual networks specified in the parameter array. The parameters for subscription, resource group and location are copied from the input parameter array into unique invocations of the nested template.

Since we want to create the subnets for each Vnet, they are contained in a sub-array of each Vnet in the parameters file. Instead of a resource-level copy, a parameter copy for the subnets name array associates the subnets in the parameters with the correct Vnet.

Note that this template assumes that you have created your subscriptions and the target resource groups in advance.

I hope you find this useful and look forward to your comments.

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('Deploy-',parameters('ParameterArray')[copyIndex('Vnets')].VnetName)]",
            "type": "   ",
            "resourceGroup": "[parameters('ParameterArray')[copyIndex('Vnets')].ResourceGroupName]",
            "subscriptionId": "[parameters('ParameterArray')[copyIndex('Vnets')].SubscriptionId]",
            "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/",
                            "name": "[parameters('ParameterArray')[copyIndex('Vnets')].VnetName]",
                            "location": "[parameters('ParameterArray')[copyIndex('Vnets')].Region]",
                            "properties": {
                                "addressSpace": {
                                    "addressPrefixes": [
                                        "[parameters('ParameterArray')[copyIndex('Vnets')].VnetAddressSpace]"
                                    ]
                                },
                                "copy": [
                                    {
                                        "name": "subnets",
                                        "count": "[length(parameters('ParameterArray')[copyIndex('Vnets')].Subnets)]",
                                        "input": {
                                            "name": "[parameters('ParameterArray')[copyIndex('Vnets')].Subnets[copyIndex('subnets')].name]",
                                            "properties": {
                                                "addressPrefix": "[parameters('ParameterArray')[copyIndex('Vnets')].Subnets[copyIndex('subnets')].addressPrefix]"
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        }
    ],
"outputs": {}
}
{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "0.0.0.1",
    "parameters": {
        "ParameterArray": {
            "value": [
                {
                    "VnetName": "VnetInSubA",
                    "ResourceGroupName": "RgInSubA",
                    "SubscriptionId": "ffffffff-0000-0000-0000-aaaaaaaaaaaa",
                    "VnetAddressSpace": "10.66.0.0/16",
                    "Region": "eastus2",
                    "Subnets": [
                        {
                            "name": "subnet-10-66-1-0-24",
                            "addressPrefix": "10.66.1.0/24"
                        },
                        {
                            "name": "subnet-10-66-1-0-24",
                            "addressPrefix": "10.66.2.0/24"
                        },
                        {
                            "name": "subnet-10-66-3-0-24",
                            "addressPrefix": "10.66.3.0/24"
                        },
                        {
                            "name": "subnet-10-66-4-0-24",
                            "addressPrefix": "10.66.4.0/24"
                        },
                        {
                            "name": "subnet-10-66-5-0-24",
                            "addressPrefix": "10.66.5.0/24"
                        }
                    ]
                },
                {
                    "VnetName": "VnetInSubB",
                    "ResourceGroupName": "RgInSubB",
                    "SubscriptionId": "ffffffff-0000-0000-0000-bbbbbbbbbbbb",
                    "VnetAddressSpace": "10.64.0.0/16",
                    "Region": "eastus",
                    "Subnets": [
                        {
                            "name": "subnet-10-64-1-0-slash-24",
                            "addressPrefix": "10.64.1.0/24"
                        },
                        {
                            "name": "subnet-10-64-2-0-slash-24",
                            "addressPrefix": "10.64.2.0/24"
                        },
                        {
                            "name": "subnet-10-64-3-0-slash-24",
                            "addressPrefix": "10.64.3.0/24"
                        },
                        {
                            "name": "subnet-10-64-4-0-slash-24",
                            "addressPrefix": "10.64.4.0/24"
                        },
                        {
                            "name": "subnet-10-64-5-0-slash-24",
                            "addressPrefix": "10.64.5.0/24"
                        },
                        {
                            "name": "subnet-10-64-6-0-slash-24",
                            "addressPrefix": "10.64.6.0/24"
                        }
                    ]
                }
            ]
        }
    }
}

 


Posted

in

, , ,

by

Comments

4 responses to “How to create Azure virtual networks”

  1. binoy Avatar
    binoy

    Hi Alex,
    This solved one of my Issues. But if I have to Give it an NSG (as an Example. How will it work. Specifically if the NSG is in a different SUb and RG, how will you create the Resource ID?

    1. Alex Neihaus Avatar
      Alex Neihaus

      You might be interested in about creating Azure NSGs

  2. NA Avatar
    NA

    Hi Alex.
    Thank you for this wonderful template. I was wondering why you’re template works without deleting the parent Vnet when adding additional subnet. Most of users are facing this issue :
    https://feedback.azure.com/forums/217313-networking/suggestions/18758545-support-vnet-re-deployment-without-destroying-subn

    1. Alex Neihaus Avatar
      Alex Neihaus

      I believe it’s because I’ve specified “mode”: “Incremental” in the “outer” template, which causes each nested template execution to be run in incremental mode instead of complete mode.

      Thanks for the positive feedback!

      Alex

Leave a Reply

Your email address will not be published. Required fields are marked *