Azure tutorial template to create UDRs and associate them with subnets

This post describes a sample Azure template to create a user-defined route (UDR) in an Azure virtual network (Vnet) and associate that newly created route with a subnet. This sample JSON Azure Resource Manager (ARM) template is part of a series. The first post described how to create Azure Vnets in an ARM template. The second described how to peer two Azure virtual networks. The last post in the series is a sample template to create Azure Network Security Groups (NSG).

I also posted a way to create Vnets in PowerShell as a way to contrast creating Azure networking resources in JSON vs. PowerShell. What makes these samples different from others you might find are that they are designed to work across multiple Azure subscriptions. Also unlike most sample templates you will find, this ARM template example allows you to associate the newly created UDRs with subnets in a single deployment.

As I discovered during the development of these Azure templates, you are limited to accessing five Azure subscriptions in a single deployment. However, within those limits, you can create as many UDRs and subnet associations as you wish. And when you are finished, your parameter input becomes the as-built documentation of your Azure virtual network.

UDRs are the workhorses of routing in Azure Vnets. They allow you to do things like route all traffic to a gateway of your choice (like a CheckPoint or Palo Alto firewall appliance) or to a resource that’s acting as an internal load balancer. In short, if you are doing any kind of enterprise networking in Azure, you are going to need to configure UDRs and associate them with the subnets whose traffic routing should be modified. That’s especially the case in more security-conscious environments where you might need to isolate subnets from each other or you are using UDRs to route traffic to a central traffic monitoring appliance.

As with my other sample ARM templates in this series, this example uses the following techniques:

  • It is a nested template, which means that the “outer” type of Microsoft.Resources/deployment will enable you to access multiple subscriptions (up to five) in the template.
  • It uses the copy function to create a runtime deployment for each subnet described in the parameter file (here, named ParameterArray).
  • The names for resources are very important in this template. Note that the way this template works is that a copy function counts the number of outer (subnet) items in the parameter array and then in the nested template, a copyindex function creates the UDR for each route defined in the inner array. These names are then used in Microsoft.Network/virtualNetworks/subnets to associate the route to the appropriate subnet.
  • In this sample, a series of database subnets have all their traffic (0.0.0.0) routed to a subnet in a different Vnet. This demonstrates how one might configure a series of DBMSs behind an internal firewall.
  • In the parameter file, there is an outer array of subnets and an inner array (for each subnet) of the routes for that subnet. Properties in the routes are from Microsoft.Network/routeTables/routes. Properties for the other resources are self-evident. But all names, for example, for resource group, Vnet and subscription must match exactly and/or be present before you run this template.
  • When I deploy this template, I use a “dummy” subscription and a “dummy” resource group to hold the deployment while resources are deployed to other subscriptions. That limits you to four of those other subscriptions so keep your parameter file input limited to less than four total if you deploy into different subscriptions than in the parameters or five if the deployment subscription will contain some of the routes you wish to create.

As always, good luck and I hope this works for you.

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",?            "type": "Microsoft.Resources/deployments",?            "copy": {?                "name": "Udrs",?                "count": "[length(parameters('ParameterArray'))]"?            },?            "name": "[concat('Deploy-Udr-in-',parameters('ParameterArray')[copyIndex('Udrs')].Subnet)]",?            "subscriptionId": "[parameters('ParameterArray')[copyIndex('Udrs')].SubscriptionId]",?            "resourceGroup": "[parameters('ParameterArray')[copyIndex('Udrs')].ResourceGroupName]",?            "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/routeTables",?                            "name": "[concat('Udr-',parameters('ParameterArray')[copyIndex('Udrs')].Subnet)]",?                            "location": "[parameters('ParameterArray')[copyIndex('Udrs')].Region]",?                            "properties": {?                                "copy": [?                                    {?                                        "name": "routes",?                                        "count": "[length(parameters('ParameterArray')[copyIndex('Udrs')].routes)]",?                                        "input": {?                                            "name": "[parameters('ParameterArray')[copyIndex('Udrs')].routes[copyIndex('routes')].name]",?                                            "properties": {?                                                "addressPrefix": "[parameters('ParameterArray')[copyIndex('Udrs')].routes[copyIndex('routes')].addressPrefix]",?                                                "nextHopType": "[parameters('ParameterArray')[copyIndex('Udrs')].routes[copyIndex('routes')].nextHopType]",?                                                "nextHopIpAddress": "[parameters('ParameterArray')[copyIndex('Udrs')].routes[copyIndex('routes')].nextHopIpAddress]"?                                            }?                                        }?                                    }?                                ]?                            }?                        },?                        {?                            "apiVersion": "2018-03-01",?                            "type": "Microsoft.Network/virtualNetworks/subnets",?                            "name": "[concat(parameters('ParameterArray')[copyIndex('Udrs')].VnetName, '/', parameters('ParameterArray')[copyIndex('Udrs')].subnet)]",?                            "dependsOn": [?                                "[concat('Udr-',parameters('ParameterArray')[copyIndex('Udrs')].Subnet)]"?                            ],?                            "location": "[parameters('ParameterArray')[copyIndex('Udrs')].Region]",?                            "properties": {?                                "addressPrefix": "[parameters('ParameterArray')[copyIndex('Udrs')].SubnetAddressPrefix]",?                                "routeTable": {?                                    "id": "[resourceId(parameters('ParameterArray')[copyIndex('Udrs')].SubscriptionId,parameters('ParameterArray')[copyIndex('Udrs')].ResourceGroupName,'Microsoft.Network/routeTables',concat('Udr-',parameters('ParameterArray')[copyIndex('Udrs')].Subnet))]"?                                }?                            }?                        }?                    ]?                }?            }?        }?    ],?    "outputs": {}?}??{?    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",?    "contentVersion": "0.0.0.1",?    "parameters": {?        "ParameterArray": {?            "value": [?                {?                    "Subnet": "Subnet-10-120-24-0-26-SQL-Server-1",?                    "SubnetAddressPrefix": "10.120.24.0/26",?                    "VnetName": "VnetSharedDatabasesDev",?                    "ResourceGroupName": "RgSharedDatabasesDev",?                    "SubscriptionId": "12345678-8888-0000-1234-123456789ABC",?                    "Region": "eastus2",?                    "routes": [?                        {?                            "name": "Udr-On-Subnet-10-120-24-0-26-SQL-Server-1-To-InternalAccess",?                            "nextHopType": "VirtualAppliance",?                            "nextHopIpAddress": "10.120.8.10",?                            "addressPrefix": "0.0.0.0/0"?                        }?                    ]?                },?                {?                    "Subnet": "Subnet-10-120-24-64-26-SQL-Server-2",?                    "SubnetAddressPrefix": "10.120.24.64/26",?                    "VnetName": "VnetSharedDatabasesDev",?                    "ResourceGroupName": "RgSharedDatabasesDev",?                    "SubscriptionId": "12345678-8888-0000-1234-123456789ABC",?                    "Region": "eastus2",?                    "routes": [?                        {?                            "name": "Udr-On-Subnet-10-120-24-64-26-SQL-Server-1-To-InternalAccess",?                            "nextHopType": "VirtualAppliance",?                            "nextHopIpAddress": "10.120.8.10",?                            "addressPrefix": "0.0.0.0/0"?                        }?                    ]?                },?                {?                    "Subnet": "Subnet-10-120-24-128-26-Oracle-1",?                    "SubnetAddressPrefix": "10.120.24.128/26",?                    "VnetName": "VnetSharedDatabasesDev",?                    "ResourceGroupName": "RgSharedDatabasesDev",?                    "SubscriptionId": "12345678-8888-0000-1234-123456789ABC",?                    "Region": "eastus2",?                    "routes": [?                        {?                            "name": "Udr-On-Subnet-10-120-24-128-26-Oracle-1",?                            "nextHopType": "VirtualAppliance",?                            "nextHopIpAddress": "10.120.8.10",?                            "addressPrefix": "0.0.0.0/0"?                        }?                    ]?                },?                {?                    "Subnet": "Subnet-10-120-24-192-26-Oracle-2",?                    "SubnetAddressPrefix": "10.120.24.192/26",?                    "VnetName": "VnetSharedDatabasesDev",?                    "ResourceGroupName": "RgSharedDatabasesDev",?                    "SubscriptionId": "12345678-8888-0000-1234-123456789ABC",?                    "Region": "eastus2",?                    "routes": [?                        {?                            "name": "Udr-On-Subnet-10-120-24-192-26-Oracle-2",?                            "nextHopType": "VirtualAppliance",?                            "nextHopIpAddress": "10.120.8.10",?                            "addressPrefix": "0.0.0.0/0"?                        }?                    ]?                }??            ]?        }?    }?}

 


Posted

in

by

Comments

Leave a Reply

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