{"id":24793547,"url":"https://github.com/christopherglewis/vnet-bicep","last_synced_at":"2025-04-10T19:41:03.690Z","repository":{"id":115003934,"uuid":"360577892","full_name":"ChristopherGLewis/vNet-Bicep","owner":"ChristopherGLewis","description":"Sample ARM Bicep file to deploy vNet/Subnet without dropping Subnet during re-deployment","archived":false,"fork":false,"pushed_at":"2021-09-14T15:26:32.000Z","size":20,"stargazers_count":15,"open_issues_count":1,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-24T17:06:36.289Z","etag":null,"topics":["arm","bicep","nsg","subnets","vnets"],"latest_commit_sha":null,"homepage":"","language":"Bicep","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChristopherGLewis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-22T16:04:25.000Z","updated_at":"2024-06-14T15:15:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"8c44f226-d6be-471a-a3fe-4929b00eec21","html_url":"https://github.com/ChristopherGLewis/vNet-Bicep","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopherGLewis%2FvNet-Bicep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopherGLewis%2FvNet-Bicep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopherGLewis%2FvNet-Bicep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopherGLewis%2FvNet-Bicep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChristopherGLewis","download_url":"https://codeload.github.com/ChristopherGLewis/vNet-Bicep/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248281414,"owners_count":21077423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arm","bicep","nsg","subnets","vnets"],"created_at":"2025-01-29T21:59:48.485Z","updated_at":"2025-04-10T19:41:03.656Z","avatar_url":"https://github.com/ChristopherGLewis.png","language":"Bicep","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Virtual Network Bicep deployment\r\n\r\nThe vnet deployment used to fully deploy a network in one pass.  Currently this is problematic\r\ndue to the complexities of the NSG/RT requirements of the special networks.\r\n\r\n## Script\r\n\r\nThe script to deploy a network is `Deploy-Network.ps1`. This is a resource group\r\nbased deployment and deploys all vnets within a single RG.  This script reads a vnetParam.json\r\nfile that has a definition of the vnets as a JSON file\r\n\r\n``` PowerShell\r\n\r\n.\\Deploy-Network.ps1 -ValidateOnly\r\n.\\Deploy-Network.ps1 -SaveParameterFile  #Does not delete the Temp PARAM file\r\n\r\n```\r\n\r\n## vNet Parameters\r\n\r\nThe ARM template takes two complex parameters\r\n\r\n### VNetArray\r\n\r\nThe vNet array is a JSON array of a flat vNet object - note that extra fields are ignored\r\n\r\n``` JSON\r\n[\r\n  {\r\n    \"vNetName\": \"vnet00\",\r\n    \"vNetRG\": \"rgNetworking\",\r\n    \"vNetLocation\": \"centralUs\",\r\n    \"NetworkType\": \"Hub\",\r\n    \"vNetAddressSpace\": \"10.200.0.0/24\",\r\n    \"subnetArray\": \"...\"\r\n  },\r\n  {\r\n    \"vNetName\": \"vnet01\",\r\n    \"vNetLocation\": \"centralUs\",\r\n    \"NetworkType\": \"Spoke\",\r\n    \"vNetAddressSpace\": \"10.200.1.0/24\",\r\n    \"subnetArray\": \"...\"\r\n  }\r\n]\r\n```\r\n\r\n### SubnetArray\r\n\r\nThe subnetArray is *all* the subnets for all vnets.  Note that the serviceEndpoints,\r\nsecurityRules and routes are arrays of the actual required ARM objects\r\n\r\n``` JSON\r\n[\r\n  {\r\n    \"vNetName\": \"vnet00\",\r\n    \"subnetName\": \"GatewaySubnet\",\r\n    \"SubnetAddressSpace\": \"10.200.0.0/27\",\r\n    \"serviceEndpoints\": [],\r\n    \"securityRules\": [],\r\n    \"routes\": []\r\n  },\r\n  {\r\n    \"vNetName\": \"vnet00\",\r\n    \"subnetName\": \"AzureBastionSubnet\",\r\n    \"SubnetAddressSpace\": \"10.200.0.32/27\",\r\n    \"serviceEndpoints\": [],\r\n    \"securityRules\": [],\r\n    \"routes\": []\r\n  },\r\n...\r\n  {\r\n    \"vNetName\": \"vnet01\",\r\n    \"subnetName\": \"adtier\",\r\n    \"SubnetAddressSpace\": \"10.200.1.192/26\",\r\n    \"serviceEndpoints\": [],\r\n    \"securityRules\": [],\r\n    \"routes\": []\r\n  }\r\n]\r\n```\r\n\r\nThese objects are generated from the vnetParam.json file.\r\n\r\n#### Routes\r\n\r\nThe routes object is an array of route table entries\r\n\r\n``` JSON\r\n[\r\n  {\r\n    \"name\": \"DefaultRoute\",\r\n    \"properties\": {\r\n      \"addressPrefix\" : \"0.0.0.0/0'\",\r\n      \"nextHopType\" : \"VirtualAppliance\",\r\n      \"nextHopIpAddress\" : \"10.0.0.1\"\r\n    }\r\n  }\r\n]\r\n```\r\n\r\n#### networkSecurityGroups\r\n\r\nThe securityRules object is an array of rules\r\n\r\n``` JSON\r\n[\r\n  {\r\n    \"name\" : \"default-allow-rdp\",\r\n    \"properties\" : {\r\n      \"priority\": 1010,\r\n      \"access\": \"Allow\",\r\n      \"direction\": \"Inbound\",\r\n      \"protocol\": \"Tcp\",\r\n      \"sourcePortRange\": \"*\",\r\n      \"sourceAddressPrefix\": \"VirtualNetwork\",\r\n      \"destinationAddressPrefix\": \"*\",\r\n      \"destinationPortRange\": \"3389\"\r\n    }\r\n  }\r\n]\r\n```\r\n\r\n#### ServiceEndPoints\r\n\r\nThe serviceEndPoints object is an array of service\r\n\r\n``` JSON\r\n[\r\n  {\r\n    \"locations\": [\r\n      \"centralus\",\r\n      \"eastus2\"\r\n    ],\r\n    \"service\": \"Microsoft.Sql\"\r\n  },\r\n  {\r\n    \"locations\": [\r\n      \"centralus\",\r\n      \"eastus2\"\r\n    ],\r\n    \"service\": \"Microsoft.Storage\"\r\n  },\r\n  {\r\n    \"locations\": [\r\n      \"centralus\",\r\n      \"eastus2\"\r\n    ],\r\n    \"service\": \"Microsoft.KeyVault\"\r\n  }\r\n]\r\n```\r\n\r\n## NOTES\r\n\r\nEven though this is an incremental deployment, it is a **disruptive** deployment of a\r\nvNet in Azure.\r\n\r\nThis deployment keeps the subnets but drops the RouteTable, NSG and Service Endpoints\r\nfrom the subnet and re-adds them back later.  It will also drop any subnet delegations\r\nsince this code doesn't support that at this time.\r\n\r\nAnother thing to note is that this does allow for resizing of the base vNet and\r\nsubnets.  The base vnet can grow and shrink as long as none of the subnets are\r\nout of the new range.  Subnets can be resized within the vNet, but can't cause\r\noverlaps and cannot be resized if they have any resources attached to them (NICs,\r\nPaaS Services etc).  This fundamentally restricts the usability of *any* vNet code\r\nfor CI/CD IaC processes if there is an address space change needed to a subnet\r\nthat has attached objects.\r\n\r\nSee this link: https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-modes#incremental-mode for further details.\r\n\r\n### Bicep Notes\r\n\r\nThere are some tricks that are used in the bicep files to work with this.\r\n\r\n### Subnet Modules\r\n\r\nThere are four subnet modules based on the NSG/RT requirements.  This is required\r\nbecause the route/NSG fields will not take a `null` or `''` for the resource id.\r\n\r\n``` ARM\r\nrouteTable: {\r\n      id: \"\"       \u003c-- Causes errors\r\n}\r\n\r\n-or-\r\n\r\nrouteTable:  null() \u003c-- Causes errors\r\n```\r\n\r\nThis requires four subnet modules (subnet-rt, subnet-nsg, subnet-both and subnet-none).\r\n\r\n### RouteTable and NetworkSecurityGroup modules\r\n\r\nThere are also modules for the RT's and NSG's that can be used to create blank\r\ntables or full tables if the appropriate arrays of objects are passed to them.\r\n\r\nThe details of the object requirements are documented in each file, and are driven\r\nby the object formats here:\r\n\r\n* https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=json#securityrulepropertiesformat-object\r\n\r\n* https://docs.microsoft.com/en-us/azure/templates/microsoft.network/routetables/routes?tabs=json#routepropertiesformat-object\r\n\r\n### Loops\r\n\r\nThe main vNet.Bicep file runs a series of loops to build out each type of object.\r\n\r\nThe vNet loop is pretty simple with vnet name and address.  There is a section that minimally\r\ndefines the subnets for the vnet with address space only.  This prevents the subnets from\r\nbeing dropped on re-deployments, but will remove all route tables and NSG tables from\r\nthe subnets *until they are reattached later in the deployment*.\r\n\r\nThe secondary rt/nsg/subnet loops use conditionals to determine what type of subnet\r\nto deploy for the special subnets.  Because ARM evaluates loops before conditionals,\r\neach of these loops runs through the entire subnetArray and only gets processed for\r\nthe special subnets that require the particular configuration via the conditional.\r\nYou should note that the names of the loops are fully qualified (\"loop-vnet-subnet-index\")\r\nto ensure uniqueness at the resource name level for deployment.\r\n\r\nAll in all this process would be *much* simpler if ARM allowed a null reference for\r\na route table or NSG ID.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristopherglewis%2Fvnet-bicep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristopherglewis%2Fvnet-bicep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristopherglewis%2Fvnet-bicep/lists"}