diff --git a/accelerator/.config/ALZ-Powershell-Auto.config.json b/accelerator/.config/ALZ-Powershell-Auto.config.json index 66f60d6c2..ff26e7d78 100644 --- a/accelerator/.config/ALZ-Powershell-Auto.config.json +++ b/accelerator/.config/ALZ-Powershell-Auto.config.json @@ -197,6 +197,20 @@ "order": 10, "group": "connectivity" }, + { + "name": "hub_and_spoke_multi_region", + "displayName": "Hub (Hub-and-Spoke) Multi-Region Deployment", + "templateFilePath": "./infra-as-code/bicep/modules/hubNetworking/hubNetworking-multiRegion.bicep", + "templateParametersFilePath": "./config/custom-parameters/hubNetworking.parameters.multiRegion.all.json", + "templateParametersSourceFilePath": "./infra-as-code/bicep/modules/hubNetworking/parameters/hubNetworking.parameters.az.multiRegion.all.json", + "subscriptionId": "CONNECTIVITY_SUBSCRIPTION_ID", + "resourceGroupName": "CONNECTIVITY_RESOURCE_GROUP", + "networkType": "hubNetworkingMultiRegion", + "deploymentType": "resourceGroup", + "firstRunWhatIf": false, + "order": 11, + "group": "connectivity" + }, { "name": "vwan", "displayName": "Hub (VWAN) Deployment", @@ -208,7 +222,21 @@ "networkType": "vwanConnectivity", "deploymentType": "resourceGroup", "firstRunWhatIf": false, - "order": 10, + "order": 12, + "group": "connectivity" + }, + { + "name": "vwan_multi_region", + "displayName": "Hub (VWAN) Multi-Region Deployment", + "templateFilePath": "./infra-as-code/bicep/modules/vwanConnectivity/vwanConnectivity.bicep", + "templateParametersFilePath": "./config/custom-parameters/vwanConnectivity.parameters.multiRegion.all.json", + "templateParametersSourceFilePath": "./infra-as-code/bicep/modules/vwanConnectivity/parameters/vwanConnectivity.parameters.az.multiRegion.all.json", + "subscriptionId": "CONNECTIVITY_SUBSCRIPTION_ID", + "resourceGroupName": "CONNECTIVITY_RESOURCE_GROUP", + "networkType": "vwanConnectivityMultiRegion", + "deploymentType": "resourceGroup", + "firstRunWhatIf": false, + "order": 13, "group": "connectivity" } ], @@ -284,6 +312,27 @@ ], "validation": "azure_location" }, + "SecondaryLocation":{ + "source": "input", + "type": "string", + "description": "Secondary deployment location. (e.g 'westeurope')", + "Value": "", + "Targets": [ + { + "Name": "parSecondaryLocation.value", + "Destination": "Parameters" + }, + { + "Name": "parVirtualWanHubs.value[1].parHubLocation", + "Destination": "Parameters" + }, + { + "Name": "SECONDARYLOCATION", + "Destination": "Environment" + } + ], + "validation": "azure_location" + }, "Environment": { "source": "input", "type": "string", @@ -505,6 +554,17 @@ } ] }, + "HubNetworkNameSecondary": { + "source": "powershell", + "type": "string", + "Value": "alz-hub-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parHubNetworkNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, "VirtualIdToLink": { "source": "powershell", "type": "string", @@ -538,6 +598,17 @@ } ] }, + "AzFirewallNameSecondary": { + "source": "powershell", + "type": "string", + "Value": "alz-azfw-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parAzFirewallNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, "FirewallPoliciesName": { "source": "powershell", "type": "string", @@ -549,6 +620,17 @@ } ] }, + "FirewallPoliciesNameSecondary": { + "source": "powershell", + "type": "string", + "Value": "alz-azfwpolicy-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parAzFirewallPoliciesNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, "AK8sPrivateLink": { "source": "powershell", "type": "string", @@ -560,6 +642,105 @@ } ] }, + "parAzBastionName": { + "source": "powershell", + "type": "string", + "Value": "alz-bastion-{%Location%}", + "Targets": [ + { + "Name": "parAzBastionName.value", + "Destination": "Parameters" + } + ] + }, + "parAzBastionNameSecondaryLocation": { + "source": "powershell", + "type": "string", + "Value": "alz-bastion-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parAzBastionNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, + "parAzBastionNsgName": { + "source": "powershell", + "type": "string", + "Value": "nsg-AzureBastionSubnet-{%Location%}", + "Targets": [ + { + "Name": "parAzBastionNsgName.value", + "Destination": "Parameters" + } + ] + }, + "parAzBastionNsgNameSecondaryLocation": { + "source": "powershell", + "type": "string", + "Value": "nsg-AzureBastionSubnet-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parAzBastionNsgNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, + "parDdosPlanName": { + "source": "powershell", + "type": "string", + "Value": "alz-ddos-plan-{%Location%}", + "Targets": [ + { + "Name": "parDdosPlanName.value", + "Destination": "Parameters" + } + ] + }, + "parDdosPlanNameSecondaryLocation": { + "source": "powershell", + "type": "string", + "Value": "alz-ddos-plan-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parDdosPlanNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, + "parHubRouteTableName": { + "source": "powershell", + "type": "string", + "Value": "alz-hub-routetable-{%Location%}", + "Targets": [ + { + "Name": "parHubRouteTableName.value", + "Destination": "Parameters" + } + ] + }, + "parHubRouteTableNameSecondaryLocation": { + "source": "powershell", + "type": "string", + "Value": "alz-hub-routetable-{%SecondaryLocation%}", + "Targets": [ + { + "Name": "parHubRouteTableNameSecondaryLocation.value", + "Destination": "Parameters" + } + ] + }, + "AK8sPrivateLinkSecondary": { + "source": "powershell", + "type": "string", + "Value": "privatelink.{%SecondaryLocation%}.azmk8s.io", + "Targets": [ + { + "Name": "parPrivateDnsZonesSecondaryLocation.value[0]", + "Destination": "Parameters" + } + ] + }, "BatchPrivateLink": { "source": "powershell", "type": "string", @@ -571,6 +752,17 @@ } ] }, + "BatchPrivateLinkSecondary": { + "source": "powershell", + "type": "string", + "Value": "privatelink.{%SecondaryLocation%}.batch.azure.com", + "Targets": [ + { + "Name": "parPrivateDnsZonesSecondaryLocation.value[1]", + "Destination": "Parameters" + } + ] + }, "KustoPrivateLink": { "source": "powershell", "type": "string", @@ -582,6 +774,17 @@ } ] }, + "KustoPrivateLinkSecondary": { + "source": "powershell", + "type": "string", + "Value": "privatelink.{%SecondaryLocation%}.kusto.windows.net", + "Targets": [ + { + "Name": "parPrivateDnsZonesSecondaryLocation.value[2]", + "Destination": "Parameters" + } + ] + }, "BackupPrivateLink": { "source": "powershell", "type": "string", @@ -593,6 +796,17 @@ } ] }, + "BackupPrivateLinkSecondary": { + "source": "powershell", + "type": "string", + "Value": "privatelink.{%SecondaryLocation%}.backup.windowsazure.com", + "Targets": [ + { + "Name": "parPrivateDnsZonesSecondaryLocation.value[3]", + "Destination": "Parameters" + } + ] + }, "ConnectivityResourceGroupName": { "source": "powershell", "type": "string", @@ -660,15 +874,30 @@ "Name": "parAzErGatewayAvailabilityZones.value", "Destination": "Parameters" }, + { + "File": "hubNetworking.parameters.multiRegion.all.json", + "Name": "parAzErGatewayAvailabilityZonesSecondaryLocation.value", + "Destination": "Parameters" + }, { "File": "hubNetworking.parameters.all.json", "Name": "parAzVpnGatewayAvailabilityZones.value", "Destination": "Parameters" }, + { + "File": "hubNetworking.parameters.multiRegion.all.json", + "Name": "parAzVpnGatewayAvailabilityZonesSecondaryLocation.value", + "Destination": "Parameters" + }, { "File": "hubNetworking.parameters.all.json", "Name": "parAzFirewallAvailabilityZones.value", "Destination": "Parameters" + }, + { + "File": "hubNetworking.parameters.multiRegion.all.json", + "Name": "parAzFirewallAvailabilityZonesSecondaryLocation.value", + "Destination": "Parameters" } ] } @@ -812,6 +1041,26 @@ ], "validation": "azure_location" }, + "SecondaryLocation": { + "source": "input", + "type": "string", + "description": "Deployment location. (e.g. 'uksouth')", + "Targets": [ + { + "Name": "parLocation.value", + "Destination": "Parameters" + }, + { + "Name": "parLocation.value", + "Destination": "Parameters" + }, + { + "Name": "SECONDARYLOCATION", + "Destination": "Environment" + } + ], + "validation": "azure_location" + }, "Environment": { "source": "input", "type": "string", diff --git a/infra-as-code/bicep/modules/hubNetworking/README.md b/infra-as-code/bicep/modules/hubNetworking/README.md index d87dedce4..4c1696be9 100644 --- a/infra-as-code/bicep/modules/hubNetworking/README.md +++ b/infra-as-code/bicep/modules/hubNetworking/README.md @@ -204,6 +204,8 @@ New-AzResourceGroupDeployment @inputObject To extend your infrastructure to [additional regions](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/considerations/regions), this module can be deployed multiple times with different parameters files to deploy additional hubs in multiple regions. The [vnetPeering module](https://github.com/Azure/ALZ-Bicep/tree/main/infra-as-code/bicep/modules/vnetPeering) can be leveraged to peer the hub networks together across the different regions. +If you want to use a single deployment targeting two regions, you can use the [hubNetworking-multiRegion.bicep](https://github.com/Azure/ALZ-Bicep/blob/main/infra-as-code/bicep/modules/hubNetworking/hubNetworking-multiRegion.bicep) file along with the [hubNetwork.parameters.az.multiRegion.all.parameters.json](https://github.com/Azure/ALZ-Bicep/blob/main/infra-as-code/bicep/modules/hubNetworking/parameters/hubNetworking.parameters.az.all.jso) file. This module uses similar parameters from the `hubNetworking` module, but the parameters specific to the secondary region are suffixed with `SecondaryLocation`. It also leverages the `vnetPeering` module to peer the two hubs together. + > For the example below, two hubs will be deployed across *eastus* and *westus* regions. 1. Duplicate the [parameters file](https://github.com/Azure/ALZ-Bicep/blob/main/infra-as-code/bicep/modules/hubNetworking/parameters/hubNetworking.parameters.az.all.json) and create a new file for the first hub in the *eastus* region **hubNetworking.parameters.az.all.eastus.json**. diff --git a/infra-as-code/bicep/modules/hubNetworking/generateddocs/hubNetworking-multiRegion.bicep.md b/infra-as-code/bicep/modules/hubNetworking/generateddocs/hubNetworking-multiRegion.bicep.md new file mode 100644 index 000000000..f7819e663 --- /dev/null +++ b/infra-as-code/bicep/modules/hubNetworking/generateddocs/hubNetworking-multiRegion.bicep.md @@ -0,0 +1,1342 @@ +# ALZ Bicep - Hub Networking Module + +ALZ Bicep Module used to set up Hub Networking + +## Parameters + +Parameter name | Required | Description +-------------- | -------- | ----------- +parLocation | No | The Azure Region to deploy the resources into. +parSecondaryLocation | Yes | The secondary Azure Region to deploy the resources into. +parCompanyPrefix | No | Prefix value which will be prepended to all resource names. +parHubNetworkName | No | Name for Hub Network. +parHubNetworkNameSecondaryLocation | No | Name for Hub Network in the secondary location. +parGlobalResourceLock | No | Global Resource Lock Configuration used for all resources deployed in this module. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parHubNetworkAddressPrefix | No | The IP address range for Hub Network. +parHubNetworkAddressPrefixSecondaryLocation | No | The IP address range for Hub Network in the secondary location. +parSubnets | No | The name, IP address range, network security group, route table and delegation serviceName for each subnet in the virtual networks. +parSubnetsSecondaryLocation | No | The name, IP address range, network security group, route table and delegation serviceName for each subnet in the virtual networks in the secondary location. +parDnsServerIps | No | Array of DNS Server IP addresses for VNet. +parDnsServerIpsSecondaryLocation | No | Array of DNS Server IP addresses for VNet in the secondary location. +parVirtualNetworkLock | No | Resource Lock Configuration for Virtual Network. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parPublicIpSku | No | Public IP Address SKU. +parPublicIpSkuSecondaryLocation | No | Public IP Address SKU in secondary location. +parPublicIpPrefix | No | Optional Prefix for Public IPs. Include a succedent dash if required. Example: prefix- +parPublicIpPrefixSecondaryLocation | No | Optional Prefix for Public IPs in secondary location. Include a succedent dash if required . Example: prefix- +parPublicIpSuffix | No | Optional Suffix for Public IPs. Include a preceding dash if required. Example: -suffix +parAzBastionEnabled | No | Switch to enable/disable Azure Bastion deployment. +parAzBastionEnabledSecondaryLocation | No | Switch to enable/disable Azure Bastion deployment in secondary location. +parAzBastionName | No | Name Associated with Bastion Service. +parAzBastionNameSecondaryLocation | No | Name Associated with Bastion Service in secondary location. +parAzBastionSku | No | Azure Bastion SKU. +parAzBastionSkuSecondaryLocation | No | Azure Bastion SKU in secondary location. +parAzBastionTunneling | No | Switch to enable/disable Bastion native client support. This is only supported when the Standard SKU is used for Bastion as documented here: https://learn.microsoft.com/azure/bastion/native-client +parAzBastionTunnelingSecondaryLocation | No | Switch to enable/disable Bastion native client support in secondary location. This is only supported when the Standard SKU is used for Bastion as documented here: https://learn.microsoft.com/azure/bastion/native-client +parAzBastionNsgName | No | Name for Azure Bastion Subnet NSG. +parAzBastionNsgNameSecondaryLocation | No | Name for Azure Bastion Subnet NSG in secondary location. +parBastionLock | No | Resource Lock Configuration for Bastion. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parDdosEnabled | No | Switch to enable/disable DDoS Network Protection deployment. +parDdosEnabledSecondaryLocation | No | Switch to enable/disable DDoS Network Protection deployment in the secondary location. +parDdosPlanName | No | DDoS Plan Name. +parDdosPlanNameSecondaryLocation | No | DDoS Plan Name in the secondary location. +parDdosLock | No | Resource Lock Configuration for DDoS Plan. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parAzFirewallEnabled | No | Switch to enable/disable Azure Firewall deployment. +parAzFirewallEnabledSecondaryLocation | No | Switch to enable/disable Azure Firewall deployment in the secondary location. +parAzFirewallName | No | Azure Firewall Name. +parAzFirewallNameSecondaryLocation | No | Azure Firewall Name in the secondary location. +parAzFirewallPoliciesEnabled | No | Set this to true for the initial deployment as one firewall policy is required. Set this to false in subsequent deployments if using custom policies. +parAzFirewallPoliciesEnabledSecondaryLocation | No | Set this to true for the initial deployment as one firewall policy is required in the secondary location. Set this to false in subsequent deployments if using custom policies. +parAzFirewallPoliciesName | No | Azure Firewall Policies Name. +parAzFirewallPoliciesNameSecondaryLocation | No | Azure Firewall Policies Name in the secondary location. +parAzFirewallPoliciesAutoLearn | No | The operation mode for automatically learning private ranges to not be SNAT. +parAzFirewallPoliciesAutoLearnSecondaryLocation | No | The operation mode for automatically learning private ranges to not be SNAT in the secondary location. +parAzFirewallPoliciesPrivateRanges | No | Private IP addresses/IP ranges to which traffic will not be SNAT. +parAzFirewallPoliciesPrivateRangesSecondaryLocation | No | Private IP addresses/IP ranges to which traffic will not be SNAT in the secondary location. +parAzFirewallTier | No | Azure Firewall Tier associated with the Firewall to deploy. +parAzFirewallTierSecondaryLocation | No | Azure Firewall Tier associated with the Firewall to deploy in the secondary location. +parAzFirewallIntelMode | No | The Azure Firewall Threat Intelligence Mode. If not set, the default value is Alert. +parAzFirewallIntelModeSecondaryLocation | No | The Azure Firewall Threat Intelligence Mode in the secondary location. If not set, the default value is Alert. +parAzFirewallCustomPublicIps | No | Optional List of Custom Public IPs, which are assigned to firewalls ipConfigurations. +parAzFirewallCustomPublicIpsSecondaryLocation | No | Optional List of Custom Public IPs, which are assigned to firewalls ipConfigurations in the secondary location. +parAzFirewallAvailabilityZones | No | Availability Zones to deploy the Azure Firewall across. Region must support Availability Zones to use. If it does not then leave empty. +parAzFirewallAvailabilityZonesSecondaryLocation | No | Availability Zones to deploy the Azure Firewall across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. +parAzErGatewayAvailabilityZones | No | Availability Zones to deploy the VPN/ER PIP across. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. +parAzErGatewayAvailabilityZonesSecondaryLocation | No | Availability Zones to deploy the VPN/ER PIP across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. +parAzVpnGatewayAvailabilityZones | No | Availability Zones to deploy the VPN/ER PIP across. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. +parAzVpnGatewayAvailabilityZonesSecondaryLocation | No | Availability Zones to deploy the VPN/ER PIP across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. +parAzFirewallDnsProxyEnabled | No | Switch to enable/disable Azure Firewall DNS Proxy. +parAzFirewallDnsProxyEnabledSecondaryLocation | No | Switch to enable/disable Azure Firewall DNS Proxy in the secndary location. +parAzFirewallDnsServers | No | Array of custom DNS servers used by Azure Firewall. +parAzFirewallDnsServersSecondaryLocation | No | Array of custom DNS servers used by Azure Firewall in the secondary location. +parAzureFirewallLock | No | Resource Lock Configuration for Azure Firewall. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parHubRouteTableName | No | Name of Route table to create for the default route of Hub. +parHubRouteTableNameSecondaryLocation | No | Name of Route table to create for the default route of Hub in the secondary location. +parDisableBgpRoutePropagation | No | Switch to enable/disable BGP Propagation on route table. +parDisableBgpRoutePropagationSecondaryLocation | No | Switch to enable/disable BGP Propagation on route table in the secondary location. +parHubRouteTableLock | No | Resource Lock Configuration for Hub Route Table. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parPrivateDnsZonesEnabled | No | Switch to enable/disable Private DNS Zones deployment. +parPrivateDnsZonesResourceGroup | No | Resource Group Name for Private DNS Zones. +parPrivateDnsZones | No | Array of DNS Zones to provision in Hub Virtual Network. Default: All known Azure Private DNS Zones +parPrivateDnsZoneAutoMergeAzureBackupZone | No | Set Parameter to false to skip the addition of a Private DNS Zone for Azure Backup. +parVirtualNetworkIdToLinkFailover | No | Resource ID of Failover VNet for Private DNS Zone VNet Failover Links +parPrivateDNSZonesLock | No | Resource Lock Configuration for Private DNS Zone(s). - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parVpnGatewayEnabled | No | Switch to enable/disable VPN virtual network gateway deployment. +parVpnGatewayEnabledSecondaryLocation | No | Switch to enable/disable VPN virtual network gateway deployment in secondary location. +parVpnGatewayConfig | No | Configuration for VPN virtual network gateway to be deployed. +parVpnGatewayConfigSecondaryLocation | No | Configuration for VPN virtual network gateway to be deployed in secondary location. +parExpressRouteGatewayEnabled | No | Switch to enable/disable ExpressRoute virtual network gateway deployment. +parExpressRouteGatewayEnabledSecondaryLocation | No | Switch to enable/disable ExpressRoute virtual network gateway deployment in secondary location. +parExpressRouteGatewayConfig | No | Configuration for ExpressRoute virtual network gateway to be deployed. +parExpressRouteGatewayConfigSecondaryLocation | No | Configuration for ExpressRoute virtual network gateway to be deployed in secondary location. +parVirtualNetworkGatewayLock | No | Resource Lock Configuration for ExpressRoute Virtual Network Gateway. - `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. - `notes` - Notes about this lock. +parTags | No | Tags you would like to be applied to all resources in this module. +parTelemetryOptOut | No | Set Parameter to true to Opt-out of deployment telemetry. +parBastionOutboundSshRdpPorts | No | Define outbound destination ports or ranges for SSH or RDP that you want to access from Azure Bastion. +parBastionOutboundSshRdpPortsSecondaryLocation | No | Define outbound destination ports or ranges for SSH or RDP that you want to access from Azure Bastion in secondary location. + +### parLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The Azure Region to deploy the resources into. + +- Default value: `[resourceGroup().location]` + +### parSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-required-orange?style=flat-square) + +The secondary Azure Region to deploy the resources into. + +### parCompanyPrefix + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Prefix value which will be prepended to all resource names. + +- Default value: `alz` + +### parHubNetworkName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name for Hub Network. + +- Default value: `[format('{0}-hub-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]` + +### parHubNetworkNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name for Hub Network in the secondary location. + +- Default value: `[format('{0}-hub-{1}', parameters('parCompanyPrefix'), parameters('parSecondaryLocation'))]` + +### parGlobalResourceLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Global Resource Lock Configuration used for all resources deployed in this module. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parHubNetworkAddressPrefix + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The IP address range for Hub Network. + +- Default value: `10.10.0.0/16` + +### parHubNetworkAddressPrefixSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The IP address range for Hub Network in the secondary location. + +- Default value: `10.20.0.0/16` + +### parSubnets + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The name, IP address range, network security group, route table and delegation serviceName for each subnet in the virtual networks. + +- Default value: ` ` + +### parSubnetsSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The name, IP address range, network security group, route table and delegation serviceName for each subnet in the virtual networks in the secondary location. + +- Default value: ` ` + +### parDnsServerIps + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Array of DNS Server IP addresses for VNet. + +### parDnsServerIpsSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Array of DNS Server IP addresses for VNet in the secondary location. + +### parVirtualNetworkLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Lock Configuration for Virtual Network. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parPublicIpSku + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Public IP Address SKU. + +- Default value: `Standard` + +- Allowed values: `Basic`, `Standard` + +### parPublicIpSkuSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Public IP Address SKU in secondary location. + +- Default value: `Standard` + +- Allowed values: `Basic`, `Standard` + +### parPublicIpPrefix + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Optional Prefix for Public IPs. Include a succedent dash if required. Example: prefix- + +### parPublicIpPrefixSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Optional Prefix for Public IPs in secondary location. Include a succedent dash if required . Example: prefix- + +### parPublicIpSuffix + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Optional Suffix for Public IPs. Include a preceding dash if required. Example: -suffix + +- Default value: `-PublicIP` + +### parAzBastionEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Azure Bastion deployment. + +- Default value: `True` + +### parAzBastionEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Azure Bastion deployment in secondary location. + +- Default value: `True` + +### parAzBastionName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name Associated with Bastion Service. + +- Default value: `[format('{0}-bastion', parameters('parCompanyPrefix'))]` + +### parAzBastionNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name Associated with Bastion Service in secondary location. + +- Default value: `[format('{0}-bastion', parameters('parCompanyPrefix'))]` + +### parAzBastionSku + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Bastion SKU. + +- Default value: `Standard` + +- Allowed values: `Basic`, `Standard` + +### parAzBastionSkuSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Bastion SKU in secondary location. + +- Default value: `Standard` + +- Allowed values: `Basic`, `Standard` + +### parAzBastionTunneling + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Bastion native client support. This is only supported when the Standard SKU is used for Bastion as documented here: https://learn.microsoft.com/azure/bastion/native-client + +- Default value: `False` + +### parAzBastionTunnelingSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Bastion native client support in secondary location. This is only supported when the Standard SKU is used for Bastion as documented here: https://learn.microsoft.com/azure/bastion/native-client + +- Default value: `False` + +### parAzBastionNsgName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name for Azure Bastion Subnet NSG. + +- Default value: `nsg-AzureBastionSubnet` + +### parAzBastionNsgNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name for Azure Bastion Subnet NSG in secondary location. + +- Default value: `nsg-AzureBastionSubnet` + +### parBastionLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Lock Configuration for Bastion. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parDdosEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable DDoS Network Protection deployment. + +- Default value: `True` + +### parDdosEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable DDoS Network Protection deployment in the secondary location. + +- Default value: `True` + +### parDdosPlanName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +DDoS Plan Name. + +- Default value: `[format('{0}-ddos-plan', parameters('parCompanyPrefix'))]` + +### parDdosPlanNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +DDoS Plan Name in the secondary location. + +- Default value: `[format('{0}-ddos-plan', parameters('parCompanyPrefix'))]` + +### parDdosLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Lock Configuration for DDoS Plan. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parAzFirewallEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Azure Firewall deployment. + +- Default value: `True` + +### parAzFirewallEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Azure Firewall deployment in the secondary location. + +- Default value: `True` + +### parAzFirewallName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Firewall Name. + +- Default value: `[format('{0}-azfw-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]` + +### parAzFirewallNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Firewall Name in the secondary location. + +- Default value: `[format('{0}-azfw-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]` + +### parAzFirewallPoliciesEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Set this to true for the initial deployment as one firewall policy is required. Set this to false in subsequent deployments if using custom policies. + +- Default value: `True` + +### parAzFirewallPoliciesEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Set this to true for the initial deployment as one firewall policy is required in the secondary location. Set this to false in subsequent deployments if using custom policies. + +- Default value: `True` + +### parAzFirewallPoliciesName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Firewall Policies Name. + +- Default value: `[format('{0}-azfwpolicy-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]` + +### parAzFirewallPoliciesNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Firewall Policies Name in the secondary location. + +- Default value: `[format('{0}-azfwpolicy-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]` + +### parAzFirewallPoliciesAutoLearn + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The operation mode for automatically learning private ranges to not be SNAT. + +- Default value: `Disabled` + +### parAzFirewallPoliciesAutoLearnSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The operation mode for automatically learning private ranges to not be SNAT in the secondary location. + +- Default value: `Disabled` + +- Allowed values: `Disabled`, `Enabled` + +### parAzFirewallPoliciesPrivateRanges + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Private IP addresses/IP ranges to which traffic will not be SNAT. + +- Allowed values: `Disabled`, `Enabled` + +### parAzFirewallPoliciesPrivateRangesSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Private IP addresses/IP ranges to which traffic will not be SNAT in the secondary location. + +### parAzFirewallTier + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Firewall Tier associated with the Firewall to deploy. + +- Default value: `Standard` + +- Allowed values: `Basic`, `Standard`, `Premium` + +### parAzFirewallTierSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Azure Firewall Tier associated with the Firewall to deploy in the secondary location. + +- Default value: `Standard` + +- Allowed values: `Basic`, `Standard`, `Premium` + +### parAzFirewallIntelMode + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The Azure Firewall Threat Intelligence Mode. If not set, the default value is Alert. + +- Default value: `Alert` + +- Allowed values: `Alert`, `Deny`, `Off` + +### parAzFirewallIntelModeSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +The Azure Firewall Threat Intelligence Mode in the secondary location. If not set, the default value is Alert. + +- Default value: `Alert` + +- Allowed values: `Alert`, `Deny`, `Off` + +### parAzFirewallCustomPublicIps + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Optional List of Custom Public IPs, which are assigned to firewalls ipConfigurations. + +### parAzFirewallCustomPublicIpsSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Optional List of Custom Public IPs, which are assigned to firewalls ipConfigurations in the secondary location. + +### parAzFirewallAvailabilityZones + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Availability Zones to deploy the Azure Firewall across. Region must support Availability Zones to use. If it does not then leave empty. + +- Allowed values: `1`, `2`, `3` + +### parAzFirewallAvailabilityZonesSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Availability Zones to deploy the Azure Firewall across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. + +- Allowed values: `1`, `2`, `3` + +### parAzErGatewayAvailabilityZones + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Availability Zones to deploy the VPN/ER PIP across. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. + +- Allowed values: `1`, `2`, `3` + +### parAzErGatewayAvailabilityZonesSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Availability Zones to deploy the VPN/ER PIP across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. + +- Allowed values: `1`, `2`, `3` + +### parAzVpnGatewayAvailabilityZones + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Availability Zones to deploy the VPN/ER PIP across. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. + +- Allowed values: `1`, `2`, `3` + +### parAzVpnGatewayAvailabilityZonesSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Availability Zones to deploy the VPN/ER PIP across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP. + +- Allowed values: `1`, `2`, `3` + +### parAzFirewallDnsProxyEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Azure Firewall DNS Proxy. + +- Default value: `True` + +### parAzFirewallDnsProxyEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Azure Firewall DNS Proxy in the secndary location. + +- Default value: `True` + +### parAzFirewallDnsServers + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Array of custom DNS servers used by Azure Firewall. + +### parAzFirewallDnsServersSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Array of custom DNS servers used by Azure Firewall in the secondary location. + +### parAzureFirewallLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + + Resource Lock Configuration for Azure Firewall. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parHubRouteTableName + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name of Route table to create for the default route of Hub. + +- Default value: `[format('{0}-hub-routetable', parameters('parCompanyPrefix'))]` + +### parHubRouteTableNameSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Name of Route table to create for the default route of Hub in the secondary location. + +- Default value: `[format('{0}-hub-routetable', parameters('parCompanyPrefix'))]` + +### parDisableBgpRoutePropagation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable BGP Propagation on route table. + +- Default value: `False` + +### parDisableBgpRoutePropagationSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable BGP Propagation on route table in the secondary location. + +- Default value: `False` + +### parHubRouteTableLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Lock Configuration for Hub Route Table. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parPrivateDnsZonesEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable Private DNS Zones deployment. + +- Default value: `True` + +### parPrivateDnsZonesResourceGroup + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Group Name for Private DNS Zones. + +- Default value: `[resourceGroup().name]` + +### parPrivateDnsZones + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Array of DNS Zones to provision in Hub Virtual Network. Default: All known Azure Private DNS Zones + +- Default value: `[format('privatelink.{0}.azmk8s.io', toLower(parameters('parLocation')))] [format('privatelink.{0}.batch.azure.com', toLower(parameters('parLocation')))] [format('privatelink.{0}.kusto.windows.net', toLower(parameters('parLocation')))] [format('privatelink.{0}.backup.windowsazure.com', toLower(parameters('parLocation')))] privatelink.adf.azure.com privatelink.afs.azure.net privatelink.agentsvc.azure-automation.net privatelink.analysis.windows.net privatelink.api.azureml.ms privatelink.azconfig.io privatelink.azure-api.net privatelink.azure-automation.net privatelink.azurecr.io privatelink.azure-devices.net privatelink.azure-devices-provisioning.net privatelink.azuredatabricks.net privatelink.azurehdinsight.net privatelink.azurehealthcareapis.com privatelink.azurestaticapps.net privatelink.azuresynapse.net privatelink.azurewebsites.net privatelink.batch.azure.com privatelink.blob.core.windows.net privatelink.cassandra.cosmos.azure.com privatelink.cognitiveservices.azure.com privatelink.database.windows.net privatelink.datafactory.azure.net privatelink.dev.azuresynapse.net privatelink.dfs.core.windows.net privatelink.dicom.azurehealthcareapis.com privatelink.digitaltwins.azure.net privatelink.directline.botframework.com privatelink.documents.azure.com privatelink.eventgrid.azure.net privatelink.file.core.windows.net privatelink.gremlin.cosmos.azure.com privatelink.guestconfiguration.azure.com privatelink.his.arc.azure.com privatelink.dp.kubernetesconfiguration.azure.com privatelink.managedhsm.azure.net privatelink.mariadb.database.azure.com privatelink.media.azure.net privatelink.mongo.cosmos.azure.com privatelink.monitor.azure.com privatelink.mysql.database.azure.com privatelink.notebooks.azure.net privatelink.ods.opinsights.azure.com privatelink.oms.opinsights.azure.com privatelink.pbidedicated.windows.net privatelink.postgres.database.azure.com privatelink.prod.migration.windowsazure.com privatelink.purview.azure.com privatelink.purviewstudio.azure.com privatelink.queue.core.windows.net privatelink.redis.cache.windows.net privatelink.redisenterprise.cache.azure.net privatelink.search.windows.net privatelink.service.signalr.net privatelink.servicebus.windows.net privatelink.siterecovery.windowsazure.com privatelink.sql.azuresynapse.net privatelink.table.core.windows.net privatelink.table.cosmos.azure.com privatelink.tip1.powerquery.microsoft.com privatelink.token.botframework.com privatelink.vaultcore.azure.net privatelink.web.core.windows.net privatelink.webpubsub.azure.com` + +### parPrivateDnsZoneAutoMergeAzureBackupZone + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Set Parameter to false to skip the addition of a Private DNS Zone for Azure Backup. + +- Default value: `True` + +### parVirtualNetworkIdToLinkFailover + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource ID of Failover VNet for Private DNS Zone VNet Failover Links + +### parPrivateDNSZonesLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Lock Configuration for Private DNS Zone(s). + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parVpnGatewayEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable VPN virtual network gateway deployment. + +- Default value: `True` + +### parVpnGatewayEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable VPN virtual network gateway deployment in secondary location. + +- Default value: `True` + +### parVpnGatewayConfig + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Configuration for VPN virtual network gateway to be deployed. + +- Default value: `@{name=[format('{0}-Vpn-Gateway-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]; gatewayType=Vpn; sku=VpnGw1; vpnType=RouteBased; generation=Generation1; enableBgp=False; activeActive=False; enableBgpRouteTranslationForNat=False; enableDnsForwarding=False; bgpPeeringAddress=; bgpsettings=; vpnClientConfiguration=}` + +### parVpnGatewayConfigSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Configuration for VPN virtual network gateway to be deployed in secondary location. + +- Default value: `@{name=[format('{0}-Vpn-Gateway-{1}', parameters('parCompanyPrefix'), parameters('parSecondaryLocation'))]; gatewayType=Vpn; sku=VpnGw1; vpnType=RouteBased; generation=Generation1; enableBgp=False; activeActive=False; enableBgpRouteTranslationForNat=False; enableDnsForwarding=False; bgpPeeringAddress=; bgpsettings=; vpnClientConfiguration=}` + +### parExpressRouteGatewayEnabled + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable ExpressRoute virtual network gateway deployment. + +- Default value: `True` + +### parExpressRouteGatewayEnabledSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Switch to enable/disable ExpressRoute virtual network gateway deployment in secondary location. + +- Default value: `True` + +### parExpressRouteGatewayConfig + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Configuration for ExpressRoute virtual network gateway to be deployed. + +- Default value: `@{name=[format('{0}-ExpressRoute-Gateway', parameters('parCompanyPrefix'))]; gatewayType=ExpressRoute; sku=ErGw1AZ; vpnType=RouteBased; vpnGatewayGeneration=None; enableBgp=False; activeActive=False; enableBgpRouteTranslationForNat=False; enableDnsForwarding=False; bgpPeeringAddress=; bgpsettings=}` + +### parExpressRouteGatewayConfigSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Configuration for ExpressRoute virtual network gateway to be deployed in secondary location. + +- Default value: `@{name=[format('{0}-ExpressRoute-Gateway', parameters('parCompanyPrefix'))]; gatewayType=ExpressRoute; sku=ErGw1AZ; vpnType=RouteBased; vpnGatewayGeneration=None; enableBgp=False; activeActive=False; enableBgpRouteTranslationForNat=False; enableDnsForwarding=False; bgpPeeringAddress=; bgpsettings=}` + +### parVirtualNetworkGatewayLock + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Resource Lock Configuration for ExpressRoute Virtual Network Gateway. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + + + +- Default value: `@{kind=None; notes=This lock was created by the ALZ Bicep Hub Networking Module.}` + +### parTags + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Tags you would like to be applied to all resources in this module. + +### parTelemetryOptOut + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Set Parameter to true to Opt-out of deployment telemetry. + +- Default value: `False` + +### parBastionOutboundSshRdpPorts + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Define outbound destination ports or ranges for SSH or RDP that you want to access from Azure Bastion. + +- Default value: `22 3389` + +### parBastionOutboundSshRdpPortsSecondaryLocation + +![Parameter Setting](https://img.shields.io/badge/parameter-optional-green?style=flat-square) + +Define outbound destination ports or ranges for SSH or RDP that you want to access from Azure Bastion in secondary location. + +- Default value: `22 3389` + +## Outputs + +Name | Type | Description +---- | ---- | ----------- +outAzFirewallPrivateIp | string | +outAzFirewallPrivateIpSecondaryLocation | string | +outAzFirewallName | string | +outAzFirewallNameSecondaryLocation | string | +outPrivateDnsZones | array | +outPrivateDnsZonesNames | array | +outDdosPlanResourceId | string | +outDdosPlanResourceIdSecondaryLocation | string | +outHubVirtualNetworkName | string | +outHubVirtualNetworkNameSecondaryLocation | string | +outHubVirtualNetworkId | string | +outHubVirtualNetworkIdSecondaryLocation | string | +outHubRouteTableId | string | +outHubRouteTableIdSecondaryLocation | string | +outHubRouteTableName | string | +outHubRouteTableNameSecondaryLocation | string | +outBastionNsgId | string | +outBastionNsgIdSecondaryLocation | string | +outBastionNsgName | string | +outBastionNsgNameSecondaryLocation | string | + +## Snippets + +### Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "template": "infra-as-code/bicep/modules/hubNetworking/hubNetworking-multiRegion.json" + }, + "parameters": { + "parLocation": { + "value": "[resourceGroup().location]" + }, + "parSecondaryLocation": { + "value": "" + }, + "parCompanyPrefix": { + "value": "alz" + }, + "parHubNetworkName": { + "value": "[format('{0}-hub-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]" + }, + "parHubNetworkNameSecondaryLocation": { + "value": "[format('{0}-hub-{1}', parameters('parCompanyPrefix'), parameters('parSecondaryLocation'))]" + }, + "parGlobalResourceLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parHubNetworkAddressPrefix": { + "value": "10.10.0.0/16" + }, + "parHubNetworkAddressPrefixSecondaryLocation": { + "value": "10.20.0.0/16" + }, + "parSubnets": { + "value": [ + { + "name": "AzureBastionSubnet", + "ipAddressRange": "10.10.15.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "GatewaySubnet", + "ipAddressRange": "10.10.252.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallSubnet", + "ipAddressRange": "10.10.254.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallManagementSubnet", + "ipAddressRange": "10.10.253.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + } + ] + }, + "parSubnetsSecondaryLocation": { + "value": [ + { + "name": "AzureBastionSubnet", + "ipAddressRange": "10.20.15.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "GatewaySubnet", + "ipAddressRange": "10.20.252.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallSubnet", + "ipAddressRange": "10.20.254.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallManagementSubnet", + "ipAddressRange": "10.20.253.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + } + ] + }, + "parDnsServerIps": { + "value": [] + }, + "parDnsServerIpsSecondaryLocation": { + "value": [] + }, + "parVirtualNetworkLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parPublicIpSku": { + "value": "Standard" + }, + "parPublicIpSkuSecondaryLocation": { + "value": "Standard" + }, + "parPublicIpPrefix": { + "value": "" + }, + "parPublicIpPrefixSecondaryLocation": { + "value": "" + }, + "parPublicIpSuffix": { + "value": "-PublicIP" + }, + "parAzBastionEnabled": { + "value": true + }, + "parAzBastionEnabledSecondaryLocation": { + "value": true + }, + "parAzBastionName": { + "value": "[format('{0}-bastion', parameters('parCompanyPrefix'))]" + }, + "parAzBastionNameSecondaryLocation": { + "value": "[format('{0}-bastion', parameters('parCompanyPrefix'))]" + }, + "parAzBastionSku": { + "value": "Standard" + }, + "parAzBastionSkuSecondaryLocation": { + "value": "Standard" + }, + "parAzBastionTunneling": { + "value": false + }, + "parAzBastionTunnelingSecondaryLocation": { + "value": false + }, + "parAzBastionNsgName": { + "value": "nsg-AzureBastionSubnet" + }, + "parAzBastionNsgNameSecondaryLocation": { + "value": "nsg-AzureBastionSubnet" + }, + "parBastionLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parDdosEnabled": { + "value": true + }, + "parDdosEnabledSecondaryLocation": { + "value": true + }, + "parDdosPlanName": { + "value": "[format('{0}-ddos-plan', parameters('parCompanyPrefix'))]" + }, + "parDdosPlanNameSecondaryLocation": { + "value": "[format('{0}-ddos-plan', parameters('parCompanyPrefix'))]" + }, + "parDdosLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parAzFirewallEnabled": { + "value": true + }, + "parAzFirewallEnabledSecondaryLocation": { + "value": true + }, + "parAzFirewallName": { + "value": "[format('{0}-azfw-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]" + }, + "parAzFirewallNameSecondaryLocation": { + "value": "[format('{0}-azfw-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]" + }, + "parAzFirewallPoliciesEnabled": { + "value": true + }, + "parAzFirewallPoliciesEnabledSecondaryLocation": { + "value": true + }, + "parAzFirewallPoliciesName": { + "value": "[format('{0}-azfwpolicy-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]" + }, + "parAzFirewallPoliciesNameSecondaryLocation": { + "value": "[format('{0}-azfwpolicy-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]" + }, + "parAzFirewallPoliciesAutoLearn": { + "value": "Disabled" + }, + "parAzFirewallPoliciesAutoLearnSecondaryLocation": { + "value": "Disabled" + }, + "parAzFirewallPoliciesPrivateRanges": { + "value": [] + }, + "parAzFirewallPoliciesPrivateRangesSecondaryLocation": { + "value": [] + }, + "parAzFirewallTier": { + "value": "Standard" + }, + "parAzFirewallTierSecondaryLocation": { + "value": "Standard" + }, + "parAzFirewallIntelMode": { + "value": "Alert" + }, + "parAzFirewallIntelModeSecondaryLocation": { + "value": "Alert" + }, + "parAzFirewallCustomPublicIps": { + "value": [] + }, + "parAzFirewallCustomPublicIpsSecondaryLocation": { + "value": [] + }, + "parAzFirewallAvailabilityZones": { + "value": [] + }, + "parAzFirewallAvailabilityZonesSecondaryLocation": { + "value": [] + }, + "parAzErGatewayAvailabilityZones": { + "value": [] + }, + "parAzErGatewayAvailabilityZonesSecondaryLocation": { + "value": [] + }, + "parAzVpnGatewayAvailabilityZones": { + "value": [] + }, + "parAzVpnGatewayAvailabilityZonesSecondaryLocation": { + "value": [] + }, + "parAzFirewallDnsProxyEnabled": { + "value": true + }, + "parAzFirewallDnsProxyEnabledSecondaryLocation": { + "value": true + }, + "parAzFirewallDnsServers": { + "value": [] + }, + "parAzFirewallDnsServersSecondaryLocation": { + "value": [] + }, + "parAzureFirewallLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parHubRouteTableName": { + "value": "[format('{0}-hub-routetable', parameters('parCompanyPrefix'))]" + }, + "parHubRouteTableNameSecondaryLocation": { + "value": "[format('{0}-hub-routetable', parameters('parCompanyPrefix'))]" + }, + "parDisableBgpRoutePropagation": { + "value": false + }, + "parDisableBgpRoutePropagationSecondaryLocation": { + "value": false + }, + "parHubRouteTableLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parPrivateDnsZonesEnabled": { + "value": true + }, + "parPrivateDnsZonesResourceGroup": { + "value": "[resourceGroup().name]" + }, + "parPrivateDnsZones": { + "value": [ + "[format('privatelink.{0}.azmk8s.io', toLower(parameters('parLocation')))]", + "[format('privatelink.{0}.batch.azure.com', toLower(parameters('parLocation')))]", + "[format('privatelink.{0}.kusto.windows.net', toLower(parameters('parLocation')))]", + "[format('privatelink.{0}.backup.windowsazure.com', toLower(parameters('parLocation')))]", + "privatelink.adf.azure.com", + "privatelink.afs.azure.net", + "privatelink.agentsvc.azure-automation.net", + "privatelink.analysis.windows.net", + "privatelink.api.azureml.ms", + "privatelink.azconfig.io", + "privatelink.azure-api.net", + "privatelink.azure-automation.net", + "privatelink.azurecr.io", + "privatelink.azure-devices.net", + "privatelink.azure-devices-provisioning.net", + "privatelink.azuredatabricks.net", + "privatelink.azurehdinsight.net", + "privatelink.azurehealthcareapis.com", + "privatelink.azurestaticapps.net", + "privatelink.azuresynapse.net", + "privatelink.azurewebsites.net", + "privatelink.batch.azure.com", + "privatelink.blob.core.windows.net", + "privatelink.cassandra.cosmos.azure.com", + "privatelink.cognitiveservices.azure.com", + "privatelink.database.windows.net", + "privatelink.datafactory.azure.net", + "privatelink.dev.azuresynapse.net", + "privatelink.dfs.core.windows.net", + "privatelink.dicom.azurehealthcareapis.com", + "privatelink.digitaltwins.azure.net", + "privatelink.directline.botframework.com", + "privatelink.documents.azure.com", + "privatelink.eventgrid.azure.net", + "privatelink.file.core.windows.net", + "privatelink.gremlin.cosmos.azure.com", + "privatelink.guestconfiguration.azure.com", + "privatelink.his.arc.azure.com", + "privatelink.dp.kubernetesconfiguration.azure.com", + "privatelink.managedhsm.azure.net", + "privatelink.mariadb.database.azure.com", + "privatelink.media.azure.net", + "privatelink.mongo.cosmos.azure.com", + "privatelink.monitor.azure.com", + "privatelink.mysql.database.azure.com", + "privatelink.notebooks.azure.net", + "privatelink.ods.opinsights.azure.com", + "privatelink.oms.opinsights.azure.com", + "privatelink.pbidedicated.windows.net", + "privatelink.postgres.database.azure.com", + "privatelink.prod.migration.windowsazure.com", + "privatelink.purview.azure.com", + "privatelink.purviewstudio.azure.com", + "privatelink.queue.core.windows.net", + "privatelink.redis.cache.windows.net", + "privatelink.redisenterprise.cache.azure.net", + "privatelink.search.windows.net", + "privatelink.service.signalr.net", + "privatelink.servicebus.windows.net", + "privatelink.siterecovery.windowsazure.com", + "privatelink.sql.azuresynapse.net", + "privatelink.table.core.windows.net", + "privatelink.table.cosmos.azure.com", + "privatelink.tip1.powerquery.microsoft.com", + "privatelink.token.botframework.com", + "privatelink.vaultcore.azure.net", + "privatelink.web.core.windows.net", + "privatelink.webpubsub.azure.com" + ] + }, + "parPrivateDnsZoneAutoMergeAzureBackupZone": { + "value": true + }, + "parVirtualNetworkIdToLinkFailover": { + "value": "" + }, + "parPrivateDNSZonesLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parVpnGatewayEnabled": { + "value": true + }, + "parVpnGatewayEnabledSecondaryLocation": { + "value": true + }, + "parVpnGatewayConfig": { + "value": { + "name": "[format('{0}-Vpn-Gateway-{1}', parameters('parCompanyPrefix'), parameters('parLocation'))]", + "gatewayType": "Vpn", + "sku": "VpnGw1", + "vpnType": "RouteBased", + "generation": "Generation1", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": 65515, + "bgpPeeringAddress": "", + "peerWeight": 5 + }, + "vpnClientConfiguration": {} + } + }, + "parVpnGatewayConfigSecondaryLocation": { + "value": { + "name": "[format('{0}-Vpn-Gateway-{1}', parameters('parCompanyPrefix'), parameters('parSecondaryLocation'))]", + "gatewayType": "Vpn", + "sku": "VpnGw1", + "vpnType": "RouteBased", + "generation": "Generation1", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": 65515, + "bgpPeeringAddress": "", + "peerWeight": 5 + }, + "vpnClientConfiguration": {} + } + }, + "parExpressRouteGatewayEnabled": { + "value": true + }, + "parExpressRouteGatewayEnabledSecondaryLocation": { + "value": true + }, + "parExpressRouteGatewayConfig": { + "value": { + "name": "[format('{0}-ExpressRoute-Gateway', parameters('parCompanyPrefix'))]", + "gatewayType": "ExpressRoute", + "sku": "ErGw1AZ", + "vpnType": "RouteBased", + "vpnGatewayGeneration": "None", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": "65515", + "bgpPeeringAddress": "", + "peerWeight": "5" + } + } + }, + "parExpressRouteGatewayConfigSecondaryLocation": { + "value": { + "name": "[format('{0}-ExpressRoute-Gateway', parameters('parCompanyPrefix'))]", + "gatewayType": "ExpressRoute", + "sku": "ErGw1AZ", + "vpnType": "RouteBased", + "vpnGatewayGeneration": "None", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": "65515", + "bgpPeeringAddress": "", + "peerWeight": "5" + } + } + }, + "parVirtualNetworkGatewayLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parTags": { + "value": {} + }, + "parTelemetryOptOut": { + "value": false + }, + "parBastionOutboundSshRdpPorts": { + "value": [ + "22", + "3389" + ] + }, + "parBastionOutboundSshRdpPortsSecondaryLocation": { + "value": [ + "22", + "3389" + ] + } + } +} +``` diff --git a/infra-as-code/bicep/modules/hubNetworking/hubNetworking-multiRegion.bicep b/infra-as-code/bicep/modules/hubNetworking/hubNetworking-multiRegion.bicep new file mode 100644 index 000000000..543f6efe6 --- /dev/null +++ b/infra-as-code/bicep/modules/hubNetworking/hubNetworking-multiRegion.bicep @@ -0,0 +1,2042 @@ +metadata name = 'ALZ Bicep - Hub Networking Module' +metadata description = 'ALZ Bicep Module used to set up Hub Networking' + +type subnetOptionsType = ({ + @description('Name of subnet.') + name: string + + @description('IP-address range for subnet.') + ipAddressRange: string + + @description('Id of Network Security Group to associate with subnet.') + networkSecurityGroupId: string? + + @description('Id of Route Table to associate with subnet.') + routeTableId: string? + + @description('Name of the delegation to create for the subnet.') + delegation: string? +})[] + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. The lock settings of the service.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None') + + @description('Optional. Notes about this lock.') + notes: string? +} + +@sys.description('The Azure Region to deploy the resources into.') +param parLocation string = resourceGroup().location + +@sys.description('The secondary Azure Region to deploy the resources into.') +param parSecondaryLocation string + +@sys.description('Prefix value which will be prepended to all resource names.') +param parCompanyPrefix string = 'alz' + +@sys.description('Name for Hub Network.') +param parHubNetworkName string = '${parCompanyPrefix}-hub-${parLocation}' + +@sys.description('Name for Hub Network in the secondary location.') +param parHubNetworkNameSecondaryLocation string = '${parCompanyPrefix}-hub-${parSecondaryLocation}' + +@sys.description('''Global Resource Lock Configuration used for all resources deployed in this module. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parGlobalResourceLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('The IP address range for Hub Network.') +param parHubNetworkAddressPrefix string = '10.10.0.0/16' + +@sys.description('The IP address range for Hub Network in the secondary location.') +param parHubNetworkAddressPrefixSecondaryLocation string = '10.20.0.0/16' + +@sys.description('The name, IP address range, network security group, route table and delegation serviceName for each subnet in the virtual networks.') +param parSubnets subnetOptionsType = [ + { + name: 'AzureBastionSubnet' + ipAddressRange: '10.10.15.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } + { + name: 'GatewaySubnet' + ipAddressRange: '10.10.252.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } + { + name: 'AzureFirewallSubnet' + ipAddressRange: '10.10.254.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } + { + name: 'AzureFirewallManagementSubnet' + ipAddressRange: '10.10.253.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } +] + +@sys.description('The name, IP address range, network security group, route table and delegation serviceName for each subnet in the virtual networks in the secondary location.') +param parSubnetsSecondaryLocation subnetOptionsType = [ + { + name: 'AzureBastionSubnet' + ipAddressRange: '10.20.15.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } + { + name: 'GatewaySubnet' + ipAddressRange: '10.20.252.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } + { + name: 'AzureFirewallSubnet' + ipAddressRange: '10.20.254.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } + { + name: 'AzureFirewallManagementSubnet' + ipAddressRange: '10.20.253.0/24' + networkSecurityGroupId: '' + routeTableId: '' + } +] + +@sys.description('Array of DNS Server IP addresses for VNet.') +param parDnsServerIps array = [] + + @sys.description('Array of DNS Server IP addresses for VNet in the secondary location.') +param parDnsServerIpsSecondaryLocation array = [] + +@sys.description('''Resource Lock Configuration for Virtual Network. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parVirtualNetworkLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Public IP Address SKU.') +@allowed([ + 'Basic' + 'Standard' +]) +param parPublicIpSku string = 'Standard' + +@sys.description('Public IP Address SKU in secondary location.') +@allowed([ + 'Basic' + 'Standard' +]) +param parPublicIpSkuSecondaryLocation string = 'Standard' + +@sys.description('Optional Prefix for Public IPs. Include a succedent dash if required. Example: prefix-') +param parPublicIpPrefix string = '' + +@sys.description('Optional Prefix for Public IPs in secondary location. Include a succedent dash if required . Example: prefix-') +param parPublicIpPrefixSecondaryLocation string = '' + +@sys.description('Optional Suffix for Public IPs. Include a preceding dash if required. Example: -suffix') +param parPublicIpSuffix string = '-PublicIP' + +@sys.description('Switch to enable/disable Azure Bastion deployment.') +param parAzBastionEnabled bool = true + +@sys.description('Switch to enable/disable Azure Bastion deployment in secondary location.') +param parAzBastionEnabledSecondaryLocation bool = true + +@sys.description('Name Associated with Bastion Service.') +param parAzBastionName string = '${parCompanyPrefix}-bastion' + +@sys.description('Name Associated with Bastion Service in secondary location.') +param parAzBastionNameSecondaryLocation string = '${parCompanyPrefix}-bastion' + +@sys.description('Azure Bastion SKU.') +@allowed([ + 'Basic' + 'Standard' +]) +param parAzBastionSku string = 'Standard' + +@sys.description('Azure Bastion SKU in secondary location.') +@allowed([ + 'Basic' + 'Standard' +]) +param parAzBastionSkuSecondaryLocation string = 'Standard' + +@sys.description('Switch to enable/disable Bastion native client support. This is only supported when the Standard SKU is used for Bastion as documented here: https://learn.microsoft.com/azure/bastion/native-client') +param parAzBastionTunneling bool = false + +@sys.description('Switch to enable/disable Bastion native client support in secondary location. This is only supported when the Standard SKU is used for Bastion as documented here: https://learn.microsoft.com/azure/bastion/native-client') +param parAzBastionTunnelingSecondaryLocation bool = false + +@sys.description('Name for Azure Bastion Subnet NSG.') +param parAzBastionNsgName string = 'nsg-AzureBastionSubnet' + +@sys.description('Name for Azure Bastion Subnet NSG in secondary location.') +param parAzBastionNsgNameSecondaryLocation string = 'nsg-AzureBastionSubnet' + +@sys.description('''Resource Lock Configuration for Bastion. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parBastionLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Switch to enable/disable DDoS Network Protection deployment.') +param parDdosEnabled bool = true + +@sys.description('Switch to enable/disable DDoS Network Protection deployment in the secondary location.') +param parDdosEnabledSecondaryLocation bool = true + +@sys.description('DDoS Plan Name.') +param parDdosPlanName string = '${parCompanyPrefix}-ddos-plan' + +@sys.description('DDoS Plan Name in the secondary location.') +param parDdosPlanNameSecondaryLocation string = '${parCompanyPrefix}-ddos-plan' + +@sys.description('''Resource Lock Configuration for DDoS Plan. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parDdosLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Switch to enable/disable Azure Firewall deployment.') +param parAzFirewallEnabled bool = true + +@sys.description('Switch to enable/disable Azure Firewall deployment in the secondary location.') +param parAzFirewallEnabledSecondaryLocation bool = true + +@sys.description('Azure Firewall Name.') +param parAzFirewallName string = '${parCompanyPrefix}-azfw-${parLocation}' + +@sys.description('Azure Firewall Name in the secondary location.') +param parAzFirewallNameSecondaryLocation string = '${parCompanyPrefix}-azfw-${parLocation}' + +@sys.description('Set this to true for the initial deployment as one firewall policy is required. Set this to false in subsequent deployments if using custom policies.') +param parAzFirewallPoliciesEnabled bool = true + +@sys.description('Set this to true for the initial deployment as one firewall policy is required in the secondary location. Set this to false in subsequent deployments if using custom policies.') +param parAzFirewallPoliciesEnabledSecondaryLocation bool = true + +@sys.description('Azure Firewall Policies Name.') +param parAzFirewallPoliciesName string = '${parCompanyPrefix}-azfwpolicy-${parLocation}' + +@sys.description('Azure Firewall Policies Name in the secondary location.') +param parAzFirewallPoliciesNameSecondaryLocation string = '${parCompanyPrefix}-azfwpolicy-${parLocation}' + +@description('The operation mode for automatically learning private ranges to not be SNAT.') +param parAzFirewallPoliciesAutoLearn string = 'Disabled' +@allowed([ + 'Disabled' + 'Enabled' +]) + +@description('The operation mode for automatically learning private ranges to not be SNAT in the secondary location.') +param parAzFirewallPoliciesAutoLearnSecondaryLocation string = 'Disabled' +@allowed([ + 'Disabled' + 'Enabled' +]) + +@description('Private IP addresses/IP ranges to which traffic will not be SNAT.') +param parAzFirewallPoliciesPrivateRanges array = [] + +@description('Private IP addresses/IP ranges to which traffic will not be SNAT in the secondary location.') +param parAzFirewallPoliciesPrivateRangesSecondaryLocation array = [] + +@sys.description('Azure Firewall Tier associated with the Firewall to deploy.') +@allowed([ + 'Basic' + 'Standard' + 'Premium' +]) +param parAzFirewallTier string = 'Standard' + +@sys.description('Azure Firewall Tier associated with the Firewall to deploy in the secondary location.') +@allowed([ + 'Basic' + 'Standard' + 'Premium' +]) +param parAzFirewallTierSecondaryLocation string = 'Standard' + +@sys.description('The Azure Firewall Threat Intelligence Mode. If not set, the default value is Alert.') +@allowed([ + 'Alert' + 'Deny' + 'Off' +]) +param parAzFirewallIntelMode string = 'Alert' + +@sys.description('The Azure Firewall Threat Intelligence Mode in the secondary location. If not set, the default value is Alert.') +@allowed([ + 'Alert' + 'Deny' + 'Off' +]) +param parAzFirewallIntelModeSecondaryLocation string = 'Alert' + +@sys.description('Optional List of Custom Public IPs, which are assigned to firewalls ipConfigurations.') +param parAzFirewallCustomPublicIps array = [] + +@sys.description('Optional List of Custom Public IPs, which are assigned to firewalls ipConfigurations in the secondary location.') +param parAzFirewallCustomPublicIpsSecondaryLocation array = [] + +@allowed([ + '1' + '2' + '3' +]) +@sys.description('Availability Zones to deploy the Azure Firewall across. Region must support Availability Zones to use. If it does not then leave empty.') +param parAzFirewallAvailabilityZones array = [] + +@allowed([ + '1' + '2' + '3' +]) +@sys.description('Availability Zones to deploy the Azure Firewall across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty.') +param parAzFirewallAvailabilityZonesSecondaryLocation array = [] + +@allowed([ + '1' + '2' + '3' +]) +@sys.description('Availability Zones to deploy the VPN/ER PIP across. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP.') +param parAzErGatewayAvailabilityZones array = [] + +@allowed([ + '1' + '2' + '3' +]) +@sys.description('Availability Zones to deploy the VPN/ER PIP across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP.') +param parAzErGatewayAvailabilityZonesSecondaryLocation array = [] + +@allowed([ + '1' + '2' + '3' +]) +@sys.description('Availability Zones to deploy the VPN/ER PIP across. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP.') +param parAzVpnGatewayAvailabilityZones array = [] + +@allowed([ + '1' + '2' + '3' +]) +@sys.description('Availability Zones to deploy the VPN/ER PIP across in the secondary location. Region must support Availability Zones to use. If it does not then leave empty. Ensure that you select a zonal SKU for the ER/VPN Gateway if using Availability Zones for the PIP.') +param parAzVpnGatewayAvailabilityZonesSecondaryLocation array = [] + +@sys.description('Switch to enable/disable Azure Firewall DNS Proxy.') +param parAzFirewallDnsProxyEnabled bool = true + +@sys.description('Switch to enable/disable Azure Firewall DNS Proxy in the secndary location.') +param parAzFirewallDnsProxyEnabledSecondaryLocation bool = true + +@sys.description('Array of custom DNS servers used by Azure Firewall.') +param parAzFirewallDnsServers array = [] + +@sys.description('Array of custom DNS servers used by Azure Firewall in the secondary location.') +param parAzFirewallDnsServersSecondaryLocation array = [] + +@sys.description(''' Resource Lock Configuration for Azure Firewall. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parAzureFirewallLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Name of Route table to create for the default route of Hub.') +param parHubRouteTableName string = '${parCompanyPrefix}-hub-routetable' + +@sys.description('Name of Route table to create for the default route of Hub in the secondary location.') +param parHubRouteTableNameSecondaryLocation string = '${parCompanyPrefix}-hub-routetable' + +@sys.description('Switch to enable/disable BGP Propagation on route table.') +param parDisableBgpRoutePropagation bool = false + +@sys.description('Switch to enable/disable BGP Propagation on route table in the secondary location.') +param parDisableBgpRoutePropagationSecondaryLocation bool = false + +@sys.description('''Resource Lock Configuration for Hub Route Table. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parHubRouteTableLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Switch to enable/disable Private DNS Zones deployment.') +param parPrivateDnsZonesEnabled bool = true + +@sys.description('Resource Group Name for Private DNS Zones.') +param parPrivateDnsZonesResourceGroup string = resourceGroup().name + +@sys.description('Array of DNS Zones to provision in Hub Virtual Network. Default: All known Azure Private DNS Zones') +param parPrivateDnsZones array = [ + 'privatelink.${toLower(parLocation)}.azmk8s.io' + 'privatelink.${toLower(parLocation)}.batch.azure.com' + 'privatelink.${toLower(parLocation)}.kusto.windows.net' + 'privatelink.${toLower(parLocation)}.backup.windowsazure.com' + 'privatelink.adf.azure.com' + 'privatelink.afs.azure.net' + 'privatelink.agentsvc.azure-automation.net' + 'privatelink.analysis.windows.net' + 'privatelink.api.azureml.ms' + 'privatelink.azconfig.io' + 'privatelink.azure-api.net' + 'privatelink.azure-automation.net' + 'privatelink.azurecr.io' + 'privatelink.azure-devices.net' + 'privatelink.azure-devices-provisioning.net' + 'privatelink.azuredatabricks.net' + 'privatelink.azurehdinsight.net' + 'privatelink.azurehealthcareapis.com' + 'privatelink.azurestaticapps.net' + 'privatelink.azuresynapse.net' + 'privatelink.azurewebsites.net' + 'privatelink.batch.azure.com' + 'privatelink.blob.core.windows.net' + 'privatelink.cassandra.cosmos.azure.com' + 'privatelink.cognitiveservices.azure.com' + 'privatelink.database.windows.net' + 'privatelink.datafactory.azure.net' + 'privatelink.dev.azuresynapse.net' + 'privatelink.dfs.core.windows.net' + 'privatelink.dicom.azurehealthcareapis.com' + 'privatelink.digitaltwins.azure.net' + 'privatelink.directline.botframework.com' + 'privatelink.documents.azure.com' + 'privatelink.eventgrid.azure.net' + 'privatelink.file.core.windows.net' + 'privatelink.gremlin.cosmos.azure.com' + 'privatelink.guestconfiguration.azure.com' + 'privatelink.his.arc.azure.com' + 'privatelink.dp.kubernetesconfiguration.azure.com' + 'privatelink.managedhsm.azure.net' + 'privatelink.mariadb.database.azure.com' + 'privatelink.media.azure.net' + 'privatelink.mongo.cosmos.azure.com' + 'privatelink.monitor.azure.com' + 'privatelink.mysql.database.azure.com' + 'privatelink.notebooks.azure.net' + 'privatelink.ods.opinsights.azure.com' + 'privatelink.oms.opinsights.azure.com' + 'privatelink.pbidedicated.windows.net' + 'privatelink.postgres.database.azure.com' + 'privatelink.prod.migration.windowsazure.com' + 'privatelink.purview.azure.com' + 'privatelink.purviewstudio.azure.com' + 'privatelink.queue.core.windows.net' + 'privatelink.redis.cache.windows.net' + 'privatelink.redisenterprise.cache.azure.net' + 'privatelink.search.windows.net' + 'privatelink.service.signalr.net' + 'privatelink.servicebus.windows.net' + 'privatelink.siterecovery.windowsazure.com' + 'privatelink.sql.azuresynapse.net' + 'privatelink.table.core.windows.net' + 'privatelink.table.cosmos.azure.com' + 'privatelink.tip1.powerquery.microsoft.com' + 'privatelink.token.botframework.com' + 'privatelink.vaultcore.azure.net' + 'privatelink.web.core.windows.net' + 'privatelink.webpubsub.azure.com' +] + +@sys.description('Set Parameter to false to skip the addition of a Private DNS Zone for Azure Backup.') +param parPrivateDnsZoneAutoMergeAzureBackupZone bool = true + +@sys.description('Resource ID of Failover VNet for Private DNS Zone VNet Failover Links') +param parVirtualNetworkIdToLinkFailover string = '' + +@sys.description('''Resource Lock Configuration for Private DNS Zone(s). + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parPrivateDNSZonesLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Switch to enable/disable VPN virtual network gateway deployment.') +param parVpnGatewayEnabled bool = true + +@sys.description('Switch to enable/disable VPN virtual network gateway deployment in secondary location.') +param parVpnGatewayEnabledSecondaryLocation bool = true + +//ASN must be 65515 if deploying VPN & ER for co-existence to work: https://docs.microsoft.com/en-us/azure/expressroute/expressroute-howto-coexist-resource-manager#limits-and-limitations +@sys.description('Configuration for VPN virtual network gateway to be deployed.') +param parVpnGatewayConfig object = { + name: '${parCompanyPrefix}-Vpn-Gateway-${parLocation}' + gatewayType: 'Vpn' + sku: 'VpnGw1' + vpnType: 'RouteBased' + generation: 'Generation1' + enableBgp: false + activeActive: false + enableBgpRouteTranslationForNat: false + enableDnsForwarding: false + bgpPeeringAddress: '' + bgpsettings: { + asn: 65515 + bgpPeeringAddress: '' + peerWeight: 5 + } + vpnClientConfiguration: {} +} + +//ASN must be 65515 if deploying VPN & ER for co-existence to work: https://docs.microsoft.com/en-us/azure/expressroute/expressroute-howto-coexist-resource-manager#limits-and-limitations +@sys.description('Configuration for VPN virtual network gateway to be deployed in secondary location.') +param parVpnGatewayConfigSecondaryLocation object = { + name: '${parCompanyPrefix}-Vpn-Gateway-${parSecondaryLocation}' + gatewayType: 'Vpn' + sku: 'VpnGw1' + vpnType: 'RouteBased' + generation: 'Generation1' + enableBgp: false + activeActive: false + enableBgpRouteTranslationForNat: false + enableDnsForwarding: false + bgpPeeringAddress: '' + bgpsettings: { + asn: 65515 + bgpPeeringAddress: '' + peerWeight: 5 + } + vpnClientConfiguration: {} +} + +@sys.description('Switch to enable/disable ExpressRoute virtual network gateway deployment.') +param parExpressRouteGatewayEnabled bool = true + +@sys.description('Switch to enable/disable ExpressRoute virtual network gateway deployment in secondary location.') +param parExpressRouteGatewayEnabledSecondaryLocation bool = true + +@sys.description('Configuration for ExpressRoute virtual network gateway to be deployed.') +param parExpressRouteGatewayConfig object = { + name: '${parCompanyPrefix}-ExpressRoute-Gateway' + gatewayType: 'ExpressRoute' + sku: 'ErGw1AZ' + vpnType: 'RouteBased' + vpnGatewayGeneration: 'None' + enableBgp: false + activeActive: false + enableBgpRouteTranslationForNat: false + enableDnsForwarding: false + bgpPeeringAddress: '' + bgpsettings: { + asn: '65515' + bgpPeeringAddress: '' + peerWeight: '5' + } +} + +@sys.description('Configuration for ExpressRoute virtual network gateway to be deployed in secondary location.') +param parExpressRouteGatewayConfigSecondaryLocation object = { + name: '${parCompanyPrefix}-ExpressRoute-Gateway' + gatewayType: 'ExpressRoute' + sku: 'ErGw1AZ' + vpnType: 'RouteBased' + vpnGatewayGeneration: 'None' + enableBgp: false + activeActive: false + enableBgpRouteTranslationForNat: false + enableDnsForwarding: false + bgpPeeringAddress: '' + bgpsettings: { + asn: '65515' + bgpPeeringAddress: '' + peerWeight: '5' + } +} + +@sys.description('''Resource Lock Configuration for ExpressRoute Virtual Network Gateway. + +- `kind` - The lock settings of the service which can be CanNotDelete, ReadOnly, or None. +- `notes` - Notes about this lock. + +''') +param parVirtualNetworkGatewayLock lockType = { + kind: 'None' + notes: 'This lock was created by the ALZ Bicep Hub Networking Module.' +} + +@sys.description('Tags you would like to be applied to all resources in this module.') +param parTags object = {} + +@sys.description('Set Parameter to true to Opt-out of deployment telemetry.') +param parTelemetryOptOut bool = false + +@sys.description('Define outbound destination ports or ranges for SSH or RDP that you want to access from Azure Bastion.') +param parBastionOutboundSshRdpPorts array = [ '22', '3389' ] + +@sys.description('Define outbound destination ports or ranges for SSH or RDP that you want to access from Azure Bastion in secondary location.') +param parBastionOutboundSshRdpPortsSecondaryLocation array = [ '22', '3389' ] + +var varSubnetMap = map(range(0, length(parSubnets)), i => { + name: parSubnets[i].name + ipAddressRange: parSubnets[i].ipAddressRange + networkSecurityGroupId: parSubnets[i].?networkSecurityGroupId ?? '' + routeTableId: parSubnets[i].?routeTableId ?? '' + delegation: parSubnets[i].?delegation ?? '' + }) + +var varSubnetMapSecondaryLocation = map(range(0, length(parSubnetsSecondaryLocation)), i => { + name: parSubnetsSecondaryLocation[i].name + ipAddressRange: parSubnetsSecondaryLocation[i].ipAddressRange + networkSecurityGroupId: parSubnetsSecondaryLocation[i].?networkSecurityGroupId ?? '' + routeTableId: parSubnetsSecondaryLocation[i].?routeTableId ?? '' + delegation: parSubnetsSecondaryLocation[i].?delegation ?? '' +}) + +var varSubnetProperties = [for subnet in varSubnetMap: { + name: subnet.name + properties: { + addressPrefix: subnet.ipAddressRange + + delegations: (empty(subnet.delegation)) ? null : [ + { + name: subnet.delegation + properties: { + serviceName: subnet.delegation + } + } + ] + + networkSecurityGroup: (subnet.name == 'AzureBastionSubnet' && parAzBastionEnabled) ? { + id: '${resourceGroup().id}/providers/Microsoft.Network/networkSecurityGroups/${parAzBastionNsgName}' + } : (empty(subnet.networkSecurityGroupId)) ? null : { + id: subnet.networkSecurityGroupId + } + + routeTable: (empty(subnet.routeTableId)) ? null : { + id: subnet.routeTableId + } + } +}] + +var varSubnetPropertiesSecondaryLocation = [for subnet in varSubnetMapSecondaryLocation: { + name: subnet.name + properties: { + addressPrefix: subnet.ipAddressRange + + delegations: (empty(subnet.delegation)) ? null : [ + { + name: subnet.delegation + properties: { + serviceName: subnet.delegation + } + } + ] + + networkSecurityGroup: (subnet.name == 'AzureBastionSubnet' && parAzBastionEnabledSecondaryLocation) ? { + id: '${resourceGroup().id}/providers/Microsoft.Network/networkSecurityGroups/${parAzBastionNsgNameSecondaryLocation}' + } : (empty(subnet.networkSecurityGroupId)) ? null : { + id: subnet.networkSecurityGroupId + } + + routeTable: (empty(subnet.routeTableId)) ? null : { + id: subnet.routeTableId + } + } +}] + +var varVpnGwConfig = ((parVpnGatewayEnabled) && (!empty(parVpnGatewayConfig)) ? parVpnGatewayConfig : json('{"name": "noconfigVpn"}')) + +var varVpnGwConfigSecondaryLocation = ((parVpnGatewayEnabledSecondaryLocation) && (!empty(parVpnGatewayConfigSecondaryLocation)) ? parVpnGatewayConfigSecondaryLocation : json('{"name": "noconfigVpn"}')) + +var varErGwConfig = ((parExpressRouteGatewayEnabled) && !empty(parExpressRouteGatewayConfig) ? parExpressRouteGatewayConfig : json('{"name": "noconfigEr"}')) + +var varErGwConfigSecondaryLocation = ((parExpressRouteGatewayEnabledSecondaryLocation) && !empty(parExpressRouteGatewayConfigSecondaryLocation) ? parExpressRouteGatewayConfigSecondaryLocation : json('{"name": "noconfigEr"}')) + +var varGwConfig = [ + varVpnGwConfig + varErGwConfig +] + +var varGwConfigSecondaryLocation = [ + varVpnGwConfigSecondaryLocation + varErGwConfigSecondaryLocation +] + +// Customer Usage Attribution Id Telemetry +var varCuaid = '2686e846-5fdc-4d4f-b533-16dcb09d6e6c' + +// ZTN Telemetry +var varZtnP1CuaId = '3ab23b1e-c5c5-42d4-b163-1402384ba2db' +var varZtnP1Trigger = (parDdosEnabled && parAzFirewallEnabled && (parAzFirewallTier == 'Premium')) ? true : false + +var varZtnP1TriggerSecondaryLocation = (parDdosEnabledSecondaryLocation && parAzFirewallEnabledSecondaryLocation && (parAzFirewallTierSecondaryLocation == 'Premium')) ? true : false + +var varAzFirewallUseCustomPublicIps = length(parAzFirewallCustomPublicIps) > 0 + +var varAzFirewallUseCustomPublicIpsSecondaryLocation = length(parAzFirewallCustomPublicIpsSecondaryLocation) > 0 + +//DDos Protection plan will only be enabled if parDdosEnabled is true. +resource resDdosProtectionPlan 'Microsoft.Network/ddosProtectionPlans@2023-02-01' = if (parDdosEnabled) { + name: parDdosPlanName + location: parLocation + tags: parTags +} + +//DDos Protection plan will only be enabled if parDdosEnabled is true. +resource resDdosProtectionPlanSecondaryLocation 'Microsoft.Network/ddosProtectionPlans@2023-02-01' = if (parDdosEnabledSecondaryLocation) { + name: parDdosPlanNameSecondaryLocation + location: parSecondaryLocation + tags: parTags +} + +// Create resource lock if parDdosEnabled is true and parGlobalResourceLock.kind != 'None' or if parDdosLock.kind != 'None' +resource resDDoSProtectionPlanLock 'Microsoft.Authorization/locks@2020-05-01' = if (parDdosEnabled && (parDdosLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resDdosProtectionPlan + name: parDdosLock.?name ?? '${resDdosProtectionPlan.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parDdosLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parDdosLock.?notes + } +} + +// Create resource lock if parDdosEnabled is true and parGlobalResourceLock.kind != 'None' or if parDdosLock.kind != 'None' +resource resDDoSProtectionPlanLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parDdosEnabledSecondaryLocation && (parDdosLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resDdosProtectionPlanSecondaryLocation + name: parDdosLock.?name ?? '${resDdosProtectionPlanSecondaryLocation.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parDdosLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parDdosLock.?notes + } +} + +resource resHubVnet 'Microsoft.Network/virtualNetworks@2024-01-01' = { + dependsOn: [ + resBastionNsg + ] + name: parHubNetworkName + location: parLocation + tags: parTags + properties: { + addressSpace: { + addressPrefixes: [ + parHubNetworkAddressPrefix + ] + } + dhcpOptions: { + dnsServers: parDnsServerIps + } + subnets: varSubnetProperties + enableDdosProtection: parDdosEnabled + ddosProtectionPlan: (parDdosEnabled) ? { + id: resDdosProtectionPlan.id + } : null + } +} + +resource resHubVnetSecondaryLocation 'Microsoft.Network/virtualNetworks@2024-01-01' = { + dependsOn: [ + resBastionNsgSecondaryLocation + ] + name: parHubNetworkNameSecondaryLocation + location: parSecondaryLocation + tags: parTags + properties: { + addressSpace: { + addressPrefixes: [ + parHubNetworkAddressPrefixSecondaryLocation + ] + } + dhcpOptions: { + dnsServers: parDnsServerIpsSecondaryLocation + } + subnets: varSubnetPropertiesSecondaryLocation + enableDdosProtection: parDdosEnabledSecondaryLocation + ddosProtectionPlan: (parDdosEnabledSecondaryLocation) ? { + id: resDdosProtectionPlanSecondaryLocation.id + } : null + } +} + +// Create a virtual network resource lock if parGlobalResourceLock.kind != 'None' or if parVirtualNetworkLock.kind != 'None' +resource resVirtualNetworkLock 'Microsoft.Authorization/locks@2020-05-01' = if (parVirtualNetworkLock.kind != 'None' || parGlobalResourceLock.kind != 'None') { + scope: resHubVnet + name: parVirtualNetworkLock.?name ?? '${resHubVnet.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parVirtualNetworkLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parVirtualNetworkLock.?notes + } +} + +// Create a virtual network resource lock if parGlobalResourceLock.kind != 'None' or if parVirtualNetworkLock.kind != 'None' +resource resVirtualNetworkLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parVirtualNetworkLock.kind != 'None' || parGlobalResourceLock.kind != 'None') { + scope: resHubVnetSecondaryLocation + name: parVirtualNetworkLock.?name ?? '${resHubVnet.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parVirtualNetworkLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parVirtualNetworkLock.?notes + } +} + +module modVnetPeering '../vnetPeering/vnetPeering.bicep' = if (!empty(parSecondaryLocation)) { + name: 'deploy-Vnet-Peering' + params: { + parSourceVirtualNetworkName: resHubVnet.name + parDestinationVirtualNetworkId: resHubVnetSecondaryLocation.id + parDestinationVirtualNetworkName: resHubVnetSecondaryLocation.name + parAllowForwardedTraffic: true + parAllowGatewayTransit: false + parAllowVirtualNetworkAccess: true + parTelemetryOptOut: parTelemetryOptOut + } +} + +module modVnetPeeringSecondaryLocation '../vnetPeering/vnetPeering.bicep' = if (!empty(parSecondaryLocation)) { + name: 'deploy-Vnet-Peering-Secondary-Location' + params: { + parSourceVirtualNetworkName: resHubVnetSecondaryLocation.name + parDestinationVirtualNetworkId: resHubVnet.id + parDestinationVirtualNetworkName: resHubVnet.name + parAllowForwardedTraffic: true + parAllowGatewayTransit: false + parAllowVirtualNetworkAccess: true + parTelemetryOptOut: parTelemetryOptOut + } +} + +module modBastionPublicIp '../publicIp/publicIp.bicep' = if (parAzBastionEnabled) { + name: 'deploy-Bastion-Public-IP' + params: { + parLocation: parLocation + parPublicIpName: '${parPublicIpPrefix}${parAzBastionName}${parPublicIpSuffix}' + parPublicIpSku: { + name: parPublicIpSku + } + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parBastionLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +} + +module modBastionPublicIpSecondaryLocation '../publicIp/publicIp.bicep' = if (parAzBastionEnabledSecondaryLocation) { + name: 'deploy-Bastion-Public-IP-Secondary-Location' + params: { + parLocation: parSecondaryLocation + parPublicIpName: '${parPublicIpPrefixSecondaryLocation}${parAzBastionNameSecondaryLocation}${parPublicIpSuffix}' + parPublicIpSku: { + name: parPublicIpSkuSecondaryLocation + } + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parBastionLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +} + +resource resBastionSubnetRef 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parAzBastionEnabled) { + parent: resHubVnet + name: 'AzureBastionSubnet' +} + +resource resBastionSubnetRefSecondaryLocation 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parAzBastionEnabledSecondaryLocation) { + parent: resHubVnetSecondaryLocation + name: 'AzureBastionSubnet' +} + +resource resBastionNsg 'Microsoft.Network/networkSecurityGroups@2024-01-01' = if (parAzBastionEnabled) { + name: parAzBastionNsgName + location: parLocation + tags: parTags + + properties: { + securityRules: [ + // Inbound Rules + { + name: 'AllowHttpsInbound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 120 + sourceAddressPrefix: 'Internet' + destinationAddressPrefix: '*' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 130 + sourceAddressPrefix: 'GatewayManager' + destinationAddressPrefix: '*' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 140 + sourceAddressPrefix: 'AzureLoadBalancer' + destinationAddressPrefix: '*' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 150 + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'DenyAllInbound' + properties: { + access: 'Deny' + direction: 'Inbound' + priority: 4096 + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + } + } + // Outbound Rules + { + name: 'AllowSshRdpOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 100 + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + protocol: '*' + sourcePortRange: '*' + destinationPortRanges: parBastionOutboundSshRdpPorts + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 110 + sourceAddressPrefix: '*' + destinationAddressPrefix: 'AzureCloud' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 120 + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + protocol: '*' + sourcePortRange: '*' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowGetSessionInformation' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 130 + sourceAddressPrefix: '*' + destinationAddressPrefix: 'Internet' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '80' + } + } + { + name: 'DenyAllOutbound' + properties: { + access: 'Deny' + direction: 'Outbound' + priority: 4096 + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + } + } + ] + } +} + +resource resBastionNsgSecondaryLocation 'Microsoft.Network/networkSecurityGroups@2024-01-01' = if (parAzBastionEnabledSecondaryLocation) { + name: parAzBastionNsgNameSecondaryLocation + location: parSecondaryLocation + tags: parTags + + properties: { + securityRules: [ + // Inbound Rules + { + name: 'AllowHttpsInbound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 120 + sourceAddressPrefix: 'Internet' + destinationAddressPrefix: '*' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 130 + sourceAddressPrefix: 'GatewayManager' + destinationAddressPrefix: '*' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 140 + sourceAddressPrefix: 'AzureLoadBalancer' + destinationAddressPrefix: '*' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + access: 'Allow' + direction: 'Inbound' + priority: 150 + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'DenyAllInbound' + properties: { + access: 'Deny' + direction: 'Inbound' + priority: 4096 + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + } + } + // Outbound Rules + { + name: 'AllowSshRdpOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 100 + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + protocol: '*' + sourcePortRange: '*' + destinationPortRanges: parBastionOutboundSshRdpPortsSecondaryLocation + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 110 + sourceAddressPrefix: '*' + destinationAddressPrefix: 'AzureCloud' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 120 + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + protocol: '*' + sourcePortRange: '*' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowGetSessionInformation' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 130 + sourceAddressPrefix: '*' + destinationAddressPrefix: 'Internet' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '80' + } + } + { + name: 'DenyAllOutbound' + properties: { + access: 'Deny' + direction: 'Outbound' + priority: 4096 + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + } + } + ] + } +} + +// Create bastion nsg resource lock if parAzBastionEnbled is true and parGlobalResourceLock.kind != 'None' or if parBastionLock.kind != 'None' +resource resBastionNsgLock 'Microsoft.Authorization/locks@2020-05-01' = if (parAzBastionEnabled && (parBastionLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resBastionNsg + name: parBastionLock.?name ?? '${resBastionNsg.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parBastionLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parBastionLock.?notes + } +} + +// Create bastion nsg resource lock if parAzBastionEnbled is true and parGlobalResourceLock.kind != 'None' or if parBastionLock.kind != 'None' +resource resBastionNsgLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parAzBastionEnabledSecondaryLocation && (parBastionLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resBastionNsgSecondaryLocation + name: parBastionLock.?name ?? '${resBastionNsgSecondaryLocation.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parBastionLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parBastionLock.?notes + } +} + + +// AzureBastionSubnet is required to deploy Bastion service. This subnet must exist in the parsubnets array if you enable Bastion Service. +// There is a minimum subnet requirement of /27 prefix. +// If you are deploying standard this needs to be larger. https://docs.microsoft.com/en-us/azure/bastion/configuration-settings#subnet +resource resBastion 'Microsoft.Network/bastionHosts@2023-02-01' = if (parAzBastionEnabled) { + location: parLocation + name: parAzBastionName + tags: parTags + sku: { + name: parAzBastionSku + } + properties: { + dnsName: uniqueString(resourceGroup().id) + enableTunneling: (parAzBastionSku == 'Standard' && parAzBastionTunneling) ? parAzBastionTunneling : false + ipConfigurations: [ + { + name: 'IpConf' + properties: { + subnet: { + id: resBastionSubnetRef.id + } + publicIPAddress: { + id: parAzBastionEnabled ? modBastionPublicIp.outputs.outPublicIpId : '' + } + } + } + ] + } +} + +// AzureBastionSubnet is required to deploy Bastion service. This subnet must exist in the parsubnets array if you enable Bastion Service. +// There is a minimum subnet requirement of /27 prefix. +// If you are deploying standard this needs to be larger. https://docs.microsoft.com/en-us/azure/bastion/configuration-settings#subnet +resource resBastionSecondaryLocation 'Microsoft.Network/bastionHosts@2024-01-01' = if (parAzBastionEnabledSecondaryLocation) { + location: parSecondaryLocation + name: parAzBastionNameSecondaryLocation + tags: parTags + sku: { + name: parAzBastionSkuSecondaryLocation + } + properties: { + dnsName: uniqueString(resourceGroup().id) + enableTunneling: (parAzBastionSkuSecondaryLocation == 'Standard' && parAzBastionTunnelingSecondaryLocation) ? parAzBastionTunnelingSecondaryLocation : false + ipConfigurations: [ + { + name: 'IpConf' + properties: { + subnet: { + id: resBastionSubnetRefSecondaryLocation.id + } + publicIPAddress: { + id: parAzBastionEnabledSecondaryLocation ? modBastionPublicIpSecondaryLocation.outputs.outPublicIpId : '' + } + } + } + ] + } +} + +// Create Bastion resource lock if parAzBastionEnabled is true and parGlobalResourceLock.kind != 'None' or if parBastionLock.kind != 'None' +resource resBastionLock 'Microsoft.Authorization/locks@2020-05-01' = if (parAzBastionEnabled && (parBastionLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resBastion + name: parBastionLock.?name ?? '${resBastion.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parBastionLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parBastionLock.?notes + } +} + +// Create Bastion resource lock if parAzBastionEnabled is true and parGlobalResourceLock.kind != 'None' or if parBastionLock.kind != 'None' +resource resBastionLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parAzBastionEnabledSecondaryLocation && (parBastionLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resBastionSecondaryLocation + name: parBastionLock.?name ?? '${resBastionSecondaryLocation.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parBastionLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parBastionLock.?notes + } +} + +resource resGatewaySubnetRef 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parVpnGatewayEnabled || parExpressRouteGatewayEnabled ) { + parent: resHubVnet + name: 'GatewaySubnet' +} + +resource resGatewaySubnetRefSecondaryLocation 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parVpnGatewayEnabledSecondaryLocation || parExpressRouteGatewayEnabledSecondaryLocation ) { + parent: resHubVnetSecondaryLocation + name: 'GatewaySubnet' +} + +module modGatewayPublicIp '../publicIp/publicIp.bicep' = [for (gateway, i) in varGwConfig: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr')) { + name: 'deploy-Gateway-Public-IP-${i}' + params: { + parLocation: parLocation + parAvailabilityZones: toLower(gateway.gatewayType) == 'expressroute' ? parAzErGatewayAvailabilityZones : toLower(gateway.gatewayType) == 'vpn' ? parAzVpnGatewayAvailabilityZones : [] + parPublicIpName: '${parPublicIpPrefix}${gateway.name}${parPublicIpSuffix}' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: parPublicIpSku + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parVirtualNetworkGatewayLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +}] + +// If the gateway is active-active, create a second public IP +module modGatewayPublicIpActiveActive '../publicIp/publicIp.bicep' = [for (gateway, i) in varGwConfig: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr') && gateway.activeActive) { + name: 'deploy-Gateway-Public-IP-ActiveActive-${i}' + params: { + parLocation: parLocation + parAvailabilityZones: toLower(gateway.gatewayType) == 'expressroute' ? parAzErGatewayAvailabilityZones : toLower(gateway.gatewayType) == 'vpn' ? parAzVpnGatewayAvailabilityZones : [] + parPublicIpName: '${parPublicIpPrefix}${gateway.name}${parPublicIpSuffix}-aa' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: parPublicIpSku + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parVirtualNetworkGatewayLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +}] + +module modGatewayPublicIpSecondaryLocation '../publicIp/publicIp.bicep' = [for (gateway, i) in varGwConfigSecondaryLocation: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr')) { + name: 'deploy-Gateway-Public-IP-Secondary-Location-${i}' + params: { + parLocation: parSecondaryLocation + parAvailabilityZones: toLower(gateway.gatewayType) == 'expressroute' ? parAzErGatewayAvailabilityZonesSecondaryLocation : toLower(gateway.gatewayType) == 'vpn' ? parAzVpnGatewayAvailabilityZonesSecondaryLocation : [] + parPublicIpName: '${parPublicIpPrefixSecondaryLocation}${gateway.name}${parPublicIpSuffix}' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: parPublicIpSkuSecondaryLocation + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parVirtualNetworkGatewayLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +}] + +// If the gateway is active-active, create a second public IP +module modGatewayPublicIpActiveActiveSecondaryLocation '../publicIp/publicIp.bicep' = [for (gateway, i) in varGwConfig: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr') && gateway.activeActive) { + name: 'deploy-Gateway-Public-IP-ActiveActive-${i}' + params: { + parLocation: parLocation + parAvailabilityZones: toLower(gateway.gatewayType) == 'expressroute' ? parAzErGatewayAvailabilityZones : toLower(gateway.gatewayType) == 'vpn' ? parAzVpnGatewayAvailabilityZones : [] + parPublicIpName: '${parPublicIpPrefix}${gateway.name}${parPublicIpSuffix}-aa' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: parPublicIpSku + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parVirtualNetworkGatewayLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +}] + +//Minumum subnet size is /27 supporting documentation https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub +resource resGateway 'Microsoft.Network/virtualNetworkGateways@2024-01-01' = [for (gateway, i) in varGwConfig: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr')) { + name: gateway.name + location: parLocation + tags: parTags + properties: { + activeActive: gateway.activeActive + enableBgp: gateway.enableBgp + enableBgpRouteTranslationForNat: gateway.enableBgpRouteTranslationForNat + enableDnsForwarding: gateway.enableDnsForwarding + bgpSettings: (gateway.enableBgp) ? gateway.bgpSettings : null + gatewayType: gateway.gatewayType + vpnGatewayGeneration: (toLower(gateway.gatewayType) == 'vpn') ? gateway.generation : 'None' + vpnType: gateway.vpnType + sku: { + name: gateway.sku + tier: gateway.sku + } + vpnClientConfiguration: (toLower(gateway.gatewayType) == 'vpn') ? { + vpnClientAddressPool: gateway.vpnClientConfiguration.?vpnClientAddressPool ?? '' + vpnClientProtocols: gateway.vpnClientConfiguration.?vpnClientProtocols ?? '' + vpnAuthenticationTypes: gateway.vpnClientConfiguration.?vpnAuthenticationTypes ?? '' + aadTenant: gateway.vpnClientConfiguration.?aadTenant ?? '' + aadAudience: gateway.vpnClientConfiguration.?aadAudience ?? '' + aadIssuer: gateway.vpnClientConfiguration.?aadIssuer ?? '' + vpnClientRootCertificates: gateway.vpnClientConfiguration.?vpnClientRootCertificates ?? '' + radiusServerAddress: gateway.vpnClientConfiguration.?radiusServerAddress ?? '' + radiusServerSecret: gateway.vpnClientConfiguration.?radiusServerSecret ?? '' + } : null + ipConfigurations: concat( + // Primary IP configuration + [ + { + id: resHubVnet.id + name: 'vnetGatewayConfig1' + properties: { + publicIPAddress: { + id: modGatewayPublicIp[i].outputs.outPublicIpId // Primary Public IP + } + subnet: { + id: resGatewaySubnetRef.id + } + } + } + ], + // Add second IP configuration if activeActive is true + gateway.activeActive ? [ + { + id: resHubVnet.id + name: 'vnetGatewayConfig2' + properties: { + publicIPAddress: { + id: modGatewayPublicIpActiveActive[i].outputs.outPublicIpId // Secondary Public IP + } + subnet: { + id: resGatewaySubnetRefSecondaryLocation.id + } + } + } + ] : [] + ) + } +}] + +//Minumum subnet size is /27 supporting documentation https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpn-gateway-settings#gwsub +resource resGatewaySecondaryLocation 'Microsoft.Network/virtualNetworkGateways@2024-01-01' = [for (gateway, i) in varGwConfigSecondaryLocation: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr')) { + name: gateway.name + location: parSecondaryLocation + tags: parTags + properties: { + activeActive: gateway.activeActive + enableBgp: gateway.enableBgp + enableBgpRouteTranslationForNat: gateway.enableBgpRouteTranslationForNat + enableDnsForwarding: gateway.enableDnsForwarding + bgpSettings: (gateway.enableBgp) ? gateway.bgpSettings : null + gatewayType: gateway.gatewayType + vpnGatewayGeneration: (toLower(gateway.gatewayType) == 'vpn') ? gateway.generation : 'None' + vpnType: gateway.vpnType + sku: { + name: gateway.sku + tier: gateway.sku + } + vpnClientConfiguration: (toLower(gateway.gatewayType) == 'vpn') ? { + vpnClientAddressPool: gateway.vpnClientConfiguration.?vpnClientAddressPool ?? '' + vpnClientProtocols: gateway.vpnClientConfiguration.?vpnClientProtocols ?? '' + vpnAuthenticationTypes: gateway.vpnClientConfiguration.?vpnAuthenticationTypes ?? '' + aadTenant: gateway.vpnClientConfiguration.?aadTenant ?? '' + aadAudience: gateway.vpnClientConfiguration.?aadAudience ?? '' + aadIssuer: gateway.vpnClientConfiguration.?aadIssuer ?? '' + vpnClientRootCertificates: gateway.vpnClientConfiguration.?vpnClientRootCertificates ?? '' + radiusServerAddress: gateway.vpnClientConfiguration.?radiusServerAddress ?? '' + radiusServerSecret: gateway.vpnClientConfiguration.?radiusServerSecret ?? '' + } : null + ipConfigurations: concat( + // Primary IP configuration + [ + { + id: resHubVnetSecondaryLocation.id + name: 'vnetGatewayConfig1' + properties: { + publicIPAddress: { + id: modGatewayPublicIpSecondaryLocation[i].outputs.outPublicIpId // Primary Public IP + } + subnet: { + id: resGatewaySubnetRefSecondaryLocation.id + } + } + } + ], + // Add second IP configuration if activeActive is true + gateway.activeActive ? [ + { + id: resHubVnetSecondaryLocation.id + name: 'vnetGatewayConfig2' + properties: { + publicIPAddress: { + id: modGatewayPublicIpActiveActiveSecondaryLocation[i].outputs.outPublicIpId // Secondary Public IP + } + subnet: { + id: resGatewaySubnetRefSecondaryLocation.id + } + } + } + ] : [] + ) + } +}] + +// Create a Virtual Network Gateway resource lock if gateway.name is not equal to noconfigVpn or noconfigEr and parGlobalResourceLock.kind != 'None' or if parVirtualNetworkGatewayLock.kind != 'None' +resource resVirtualNetworkGatewayLock 'Microsoft.Authorization/locks@2020-05-01' = [for (gateway, i) in varGwConfig: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr') && (parVirtualNetworkGatewayLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resGateway[i] + name: parVirtualNetworkGatewayLock.?name ?? '${resGateway[i].name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parVirtualNetworkGatewayLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parVirtualNetworkGatewayLock.?notes + } +}] + +// Create a Virtual Network Gateway resource lock if gateway.name is not equal to noconfigVpn or noconfigEr and parGlobalResourceLock.kind != 'None' or if parVirtualNetworkGatewayLock.kind != 'None' +resource resVirtualNetworkGatewayLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = [for (gateway, i) in varGwConfigSecondaryLocation: if ((gateway.name != 'noconfigVpn') && (gateway.name != 'noconfigEr') && (parVirtualNetworkGatewayLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resGatewaySecondaryLocation[i] + name: parVirtualNetworkGatewayLock.?name ?? '${resGatewaySecondaryLocation[i].name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parVirtualNetworkGatewayLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parVirtualNetworkGatewayLock.?notes + } +}] + +resource resAzureFirewallSubnetRef 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parAzFirewallEnabled) { + parent: resHubVnet + name: 'AzureFirewallSubnet' +} + +resource resAzureFirewallSubnetRefSecondaryLocation 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parAzFirewallEnabledSecondaryLocation) { + parent: resHubVnetSecondaryLocation + name: 'AzureFirewallSubnet' +} + +resource resAzureFirewallMgmtSubnetRef 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parAzFirewallEnabled && (contains(map(parSubnets, subnets => subnets.name), 'AzureFirewallManagementSubnet'))) { + parent: resHubVnet + name: 'AzureFirewallManagementSubnet' +} + +resource resAzureFirewallMgmtSubnetRefSecondaryLocation 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' existing = if (parAzFirewallEnabledSecondaryLocation && (contains(map(parSubnetsSecondaryLocation, subnets => subnets.name), 'AzureFirewallManagementSubnet'))) { + parent: resHubVnetSecondaryLocation + name: 'AzureFirewallManagementSubnet' +} + +module modAzureFirewallPublicIp '../publicIp/publicIp.bicep' = if (parAzFirewallEnabled) { + name: 'deploy-Firewall-Public-IP' + params: { + parLocation: parLocation + parAvailabilityZones: parAzFirewallAvailabilityZones + parPublicIpName: '${parPublicIpPrefix}${parAzFirewallName}${parPublicIpSuffix}' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: parPublicIpSku + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parAzureFirewallLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +} + +module modAzureFirewallPublicIpSecondaryLocation '../publicIp/publicIp.bicep' = if (parAzFirewallEnabledSecondaryLocation) { + name: 'deploy-Firewall-Public-IP-Secondary-Location' + params: { + parLocation: parSecondaryLocation + parAvailabilityZones: parAzFirewallAvailabilityZonesSecondaryLocation + parPublicIpName: '${parPublicIpPrefixSecondaryLocation}${parAzFirewallNameSecondaryLocation}${parPublicIpSuffix}' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: parPublicIpSkuSecondaryLocation + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parAzureFirewallLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +} + +module modAzureFirewallMgmtPublicIp '../publicIp/publicIp.bicep' = if (parAzFirewallEnabled && (contains(map(parSubnets, subnets => subnets.name), 'AzureFirewallManagementSubnet'))) { + name: 'deploy-Firewall-mgmt-Public-IP' + params: { + parLocation: parLocation + parAvailabilityZones: parAzFirewallAvailabilityZones + parPublicIpName: '${parPublicIpPrefix}${parAzFirewallName}-mgmt${parPublicIpSuffix}' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: 'Standard' + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parAzureFirewallLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +} + +module modAzureFirewallMgmtPublicIpSecondaryLocation '../publicIp/publicIp.bicep' = if (parAzFirewallEnabledSecondaryLocation && (contains(map(parSubnetsSecondaryLocation, subnets => subnets.name), 'AzureFirewallManagementSubnet'))) { + name: 'deploy-Firewall-mgmt-Public-IP-Secondary-Location' + params: { + parLocation: parSecondaryLocation + parAvailabilityZones: parAzFirewallAvailabilityZonesSecondaryLocation + parPublicIpName: '${parPublicIpPrefixSecondaryLocation}${parAzFirewallNameSecondaryLocation}-mgmt${parPublicIpSuffix}' + parPublicIpProperties: { + publicIpAddressVersion: 'IPv4' + publicIpAllocationMethod: 'Static' + } + parPublicIpSku: { + name: 'Standard' + } + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parAzureFirewallLock + parTags: parTags + parTelemetryOptOut: parTelemetryOptOut + } +} + +resource resFirewallPolicies 'Microsoft.Network/firewallPolicies@2024-01-01' = if (parAzFirewallEnabled && parAzFirewallPoliciesEnabled) { + name: parAzFirewallPoliciesName + location: parLocation + tags: parTags + properties: (parAzFirewallTier == 'Basic') ? { + sku: { + tier: parAzFirewallTier + } + snat: !empty(parAzFirewallPoliciesPrivateRanges) + ? { + autoLearnPrivateRanges: parAzFirewallPoliciesAutoLearn + privateRanges: parAzFirewallPoliciesPrivateRanges + } + : null + threatIntelMode: 'Alert' + } : { + dnsSettings: { + enableProxy: parAzFirewallDnsProxyEnabled + servers: parAzFirewallDnsServers + } + sku: { + tier: parAzFirewallTier + } + threatIntelMode: parAzFirewallIntelMode + } +} + +resource resFirewallPoliciesSecondaryLocation 'Microsoft.Network/firewallPolicies@2024-01-01' = if (parAzFirewallEnabledSecondaryLocation && parAzFirewallPoliciesEnabledSecondaryLocation) { + name: parAzFirewallPoliciesNameSecondaryLocation + location: parSecondaryLocation + tags: parTags + properties: (parAzFirewallTierSecondaryLocation == 'Basic') ? { + sku: { + tier: parAzFirewallTierSecondaryLocation + } + snat: !empty(parAzFirewallPoliciesPrivateRangesSecondaryLocation) + ? { + autoLearnPrivateRanges: parAzFirewallPoliciesAutoLearnSecondaryLocation + privateRanges: parAzFirewallPoliciesPrivateRangesSecondaryLocation + } + : null + threatIntelMode: 'Alert' + } : { + dnsSettings: { + enableProxy: parAzFirewallDnsProxyEnabledSecondaryLocation + servers: parAzFirewallDnsServersSecondaryLocation + } + sku: { + tier: parAzFirewallTierSecondaryLocation + } + threatIntelMode: parAzFirewallIntelModeSecondaryLocation + } +} + +// Create Azure Firewall Policy resource lock if parAzFirewallEnabled is true and parGlobalResourceLock.kind != 'None' or if parAzureFirewallLock.kind != 'None' +resource resFirewallPoliciesLock 'Microsoft.Authorization/locks@2020-05-01' = if (parAzFirewallEnabled && (parAzureFirewallLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resFirewallPolicies + name: parAzureFirewallLock.?name ?? '${resFirewallPolicies.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parAzureFirewallLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parAzureFirewallLock.?notes + } +} + +// Create Azure Firewall Policy resource lock if parAzFirewallEnabled is true and parGlobalResourceLock.kind != 'None' or if parAzureFirewallLock.kind != 'None' +resource resFirewallPoliciesLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parAzFirewallEnabledSecondaryLocation && (parAzureFirewallLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resFirewallPoliciesSecondaryLocation + name: parAzureFirewallLock.?name ?? '${resFirewallPoliciesSecondaryLocation.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parAzureFirewallLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parAzureFirewallLock.?notes + } +} + +// AzureFirewallSubnet is required to deploy Azure Firewall . This subnet must exist in the parsubnets array if you deploy. +// There is a minimum subnet requirement of /26 prefix. +resource resAzureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = if (parAzFirewallEnabled) { + dependsOn: [ + resGateway + ] + name: parAzFirewallName + location: parLocation + tags: parTags + zones: (!empty(parAzFirewallAvailabilityZones) ? parAzFirewallAvailabilityZones : []) + properties: parAzFirewallTier == 'Basic' ? { + ipConfigurations: varAzFirewallUseCustomPublicIps + ? map(parAzFirewallCustomPublicIps, ip => + { + name: 'ipconfig${uniqueString(ip)}' + properties: ip == parAzFirewallCustomPublicIps[0] + ? { + subnet: { + id: resAzureFirewallSubnetRef.id + } + publicIPAddress: { + id: parAzFirewallEnabled ? ip : '' + } + } + : { + publicIPAddress: { + id: parAzFirewallEnabled ? ip : '' + } + } + }) + : [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: resAzureFirewallSubnetRef.id + } + publicIPAddress: { + id: parAzFirewallEnabled ? modAzureFirewallPublicIp.outputs.outPublicIpId : '' + } + } + } + ] + managementIpConfiguration: { + name: 'mgmtIpConfig' + properties: { + publicIPAddress: { + id: parAzFirewallEnabled ? modAzureFirewallMgmtPublicIp.outputs.outPublicIpId : '' + } + subnet: { + id: resAzureFirewallMgmtSubnetRef.id + } + } + } + sku: { + name: 'AZFW_VNet' + tier: parAzFirewallTier + } + firewallPolicy: { + id: resFirewallPolicies.id + } + } : { + ipConfigurations: varAzFirewallUseCustomPublicIps + ? map(parAzFirewallCustomPublicIps, ip => + { + name: 'ipconfig${uniqueString(ip)}' + properties: ip == parAzFirewallCustomPublicIps[0] + ? { + subnet: { + id: resAzureFirewallSubnetRef.id + } + publicIPAddress: { + id: parAzFirewallEnabled ? ip : '' + } + } + : { + publicIPAddress: { + id: parAzFirewallEnabled ? ip : '' + } + } + }) + : [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: resAzureFirewallSubnetRef.id + } + publicIPAddress: { + id: parAzFirewallEnabled ? modAzureFirewallPublicIp.outputs.outPublicIpId : '' + } + } + } + ] + sku: { + name: 'AZFW_VNet' + tier: parAzFirewallTier + } + firewallPolicy: { + id: resFirewallPolicies.id + } + } +} + +// AzureFirewallSubnet is required to deploy Azure Firewall . This subnet must exist in the parsubnets array if you deploy. +// There is a minimum subnet requirement of /26 prefix. +resource resAzureFirewallSecondaryLocation 'Microsoft.Network/azureFirewalls@2024-01-01' = if (parAzFirewallEnabledSecondaryLocation) { + dependsOn: [ + resGatewaySecondaryLocation + ] + name: parAzFirewallNameSecondaryLocation + location: parSecondaryLocation + tags: parTags + zones: (!empty(parAzFirewallAvailabilityZonesSecondaryLocation) ? parAzFirewallAvailabilityZonesSecondaryLocation : []) + properties: parAzFirewallTierSecondaryLocation == 'Basic' ? { + ipConfigurations: varAzFirewallUseCustomPublicIpsSecondaryLocation + ? map(parAzFirewallCustomPublicIpsSecondaryLocation, ip => + { + name: 'ipconfig${uniqueString(ip)}' + properties: ip == parAzFirewallCustomPublicIpsSecondaryLocation[0] + ? { + subnet: { + id: resAzureFirewallSubnetRefSecondaryLocation.id + } + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? ip : '' + } + } + : { + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? ip : '' + } + } + }) + : [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: resAzureFirewallSubnetRefSecondaryLocation.id + } + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? modAzureFirewallPublicIpSecondaryLocation.outputs.outPublicIpId : '' + } + } + } + ] + managementIpConfiguration: { + name: 'mgmtIpConfig' + properties: { + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? modAzureFirewallMgmtPublicIpSecondaryLocation.outputs.outPublicIpId : '' + } + subnet: { + id: resAzureFirewallMgmtSubnetRefSecondaryLocation.id + } + } + } + sku: { + name: 'AZFW_VNet' + tier: parAzFirewallTierSecondaryLocation + } + firewallPolicy: { + id: resFirewallPoliciesSecondaryLocation.id + } + } : { + ipConfigurations: varAzFirewallUseCustomPublicIpsSecondaryLocation + ? map(parAzFirewallCustomPublicIpsSecondaryLocation, ip => + { + name: 'ipconfig${uniqueString(ip)}' + properties: ip == parAzFirewallCustomPublicIpsSecondaryLocation[0] + ? { + subnet: { + id: resAzureFirewallSubnetRefSecondaryLocation.id + } + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? ip : '' + } + } + : { + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? ip : '' + } + } + }) + : [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: resAzureFirewallSubnetRefSecondaryLocation.id + } + publicIPAddress: { + id: parAzFirewallEnabledSecondaryLocation ? modAzureFirewallPublicIpSecondaryLocation.outputs.outPublicIpId : '' + } + } + } + ] + sku: { + name: 'AZFW_VNet' + tier: parAzFirewallTierSecondaryLocation + } + firewallPolicy: { + id: resFirewallPoliciesSecondaryLocation.id + } + } +} + +// Create Azure Firewall resource lock if parAzFirewallEnabled is true and parGlobalResourceLock.kind != 'None' or if parAzureFirewallLock.kind != 'None' +resource resAzureFirewallLock 'Microsoft.Authorization/locks@2020-05-01' = if (parAzFirewallEnabled && (parAzureFirewallLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resAzureFirewall + name: parAzureFirewallLock.?name ?? '${resAzureFirewall.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parAzureFirewallLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parAzureFirewallLock.?notes + } +} + +// Create Azure Firewall resource lock if parAzFirewallEnabled is true and parGlobalResourceLock.kind != 'None' or if parAzureFirewallLock.kind != 'None' +resource resAzureFirewallLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parAzFirewallEnabledSecondaryLocation && (parAzureFirewallLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resAzureFirewallSecondaryLocation + name: parAzureFirewallLock.?name ?? '${resAzureFirewallSecondaryLocation.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parAzureFirewallLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parAzureFirewallLock.?notes + } +} + +//If Azure Firewall is enabled we will deploy a RouteTable to redirect Traffic to the Firewall. +resource resHubRouteTable 'Microsoft.Network/routeTables@2024-01-01' = if (parAzFirewallEnabled) { + name: parHubRouteTableName + location: parLocation + tags: parTags + properties: { + routes: [ + { + name: 'udr-default-azfw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: parAzFirewallEnabled ? resAzureFirewall.properties.ipConfigurations[0].properties.privateIPAddress : '' + } + } + ] + disableBgpRoutePropagation: parDisableBgpRoutePropagation + } +} + +//If Azure Firewall is enabled we will deploy a RouteTable to redirect Traffic to the Firewall. +resource resHubRouteTableSecondaryLocation 'Microsoft.Network/routeTables@2024-01-01' = if (parAzFirewallEnabledSecondaryLocation) { + name: parHubRouteTableNameSecondaryLocation + location: parSecondaryLocation + tags: parTags + properties: { + routes: [ + { + name: 'udr-default-azfw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: parAzFirewallEnabledSecondaryLocation ? resAzureFirewallSecondaryLocation.properties.ipConfigurations[0].properties.privateIPAddress : '' + } + } + ] + disableBgpRoutePropagation: parDisableBgpRoutePropagationSecondaryLocation + } +} + +// Create a Route Table if parAzFirewallEnabled is true and parGlobalResourceLock.kind != 'None' or if parHubRouteTableLock.kind != 'None' +resource resHubRouteTableLock 'Microsoft.Authorization/locks@2020-05-01' = if (parAzFirewallEnabled && (parHubRouteTableLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resHubRouteTable + name: parHubRouteTableLock.?name ?? '${resHubRouteTable.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parHubRouteTableLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parHubRouteTableLock.?notes + } +} + +// Create a Route Table if parAzFirewallEnabled is true and parGlobalResourceLock.kind != 'None' or if parHubRouteTableLock.kind != 'None' +resource resHubRouteTableLockSecondaryLocation 'Microsoft.Authorization/locks@2020-05-01' = if (parAzFirewallEnabledSecondaryLocation && (parHubRouteTableLock.kind != 'None' || parGlobalResourceLock.kind != 'None')) { + scope: resHubRouteTableSecondaryLocation + name: parHubRouteTableLock.?name ?? '${resHubRouteTableSecondaryLocation.name}-lock' + properties: { + level: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.kind : parHubRouteTableLock.kind + notes: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock.?notes : parHubRouteTableLock.?notes + } +} + +module modPrivateDnsZones '../privateDnsZones/privateDnsZones.bicep' = if (parPrivateDnsZonesEnabled) { + name: 'deploy-Private-DNS-Zones' + scope: resourceGroup(parPrivateDnsZonesResourceGroup) + params: { + parLocation: parLocation + parTags: parTags + parVirtualNetworkIdToLink: resHubVnet.id + parVirtualNetworkIdToLinkFailover: parVirtualNetworkIdToLinkFailover + parPrivateDnsZones: parPrivateDnsZones + parPrivateDnsZoneAutoMergeAzureBackupZone: parPrivateDnsZoneAutoMergeAzureBackupZone + parResourceLockConfig: (parGlobalResourceLock.kind != 'None') ? parGlobalResourceLock : parPrivateDNSZonesLock + parTelemetryOptOut: parTelemetryOptOut + } +} + +// Optional Deployments for Customer Usage Attribution +module modCustomerUsageAttribution '../../CRML/customerUsageAttribution/cuaIdResourceGroup.bicep' = if (!parTelemetryOptOut) { + #disable-next-line no-loc-expr-outside-params //Only to ensure telemetry data is stored in same location as deployment. See https://github.com/Azure/ALZ-Bicep/wiki/FAQ#why-are-some-linter-rules-disabled-via-the-disable-next-line-bicep-function for more information + name: 'pid-${varCuaid}-${uniqueString(resourceGroup().location)}' + params: {} +} + +module modCustomerUsageAttributionZtnP1 '../../CRML/customerUsageAttribution/cuaIdResourceGroup.bicep' = if (!parTelemetryOptOut && (varZtnP1Trigger || varZtnP1TriggerSecondaryLocation)) { + #disable-next-line no-loc-expr-outside-params //Only to ensure telemetry data is stored in same location as deployment. See https://github.com/Azure/ALZ-Bicep/wiki/FAQ#why-are-some-linter-rules-disabled-via-the-disable-next-line-bicep-function for more information + name: 'pid-${varZtnP1CuaId}-${uniqueString(resourceGroup().location)}' + params: {} +} + +//If Azure Firewall is enabled we will deploy a RouteTable to redirect Traffic to the Firewall. +output outAzFirewallPrivateIp string = parAzFirewallEnabled ? resAzureFirewall.properties.ipConfigurations[0].properties.privateIPAddress : '' +output outAzFirewallPrivateIpSecondaryLocation string = parAzFirewallEnabledSecondaryLocation ? resAzureFirewallSecondaryLocation.properties.ipConfigurations[0].properties.privateIPAddress : '' + + +//If Azure Firewall is enabled we will deploy a RouteTable to redirect Traffic to the Firewall. +output outAzFirewallName string = parAzFirewallEnabled ? parAzFirewallName : '' +output outAzFirewallNameSecondaryLocation string = parAzFirewallEnabledSecondaryLocation ? parAzFirewallNameSecondaryLocation : '' + +output outPrivateDnsZones array = (parPrivateDnsZonesEnabled ? modPrivateDnsZones.outputs.outPrivateDnsZones : []) +output outPrivateDnsZonesNames array = (parPrivateDnsZonesEnabled ? modPrivateDnsZones.outputs.outPrivateDnsZonesNames : []) + +output outDdosPlanResourceId string = resDdosProtectionPlan.id +output outDdosPlanResourceIdSecondaryLocation string = resDdosProtectionPlanSecondaryLocation.id + +output outHubVirtualNetworkName string = resHubVnet.name +output outHubVirtualNetworkNameSecondaryLocation string = resHubVnetSecondaryLocation.name + +output outHubVirtualNetworkId string = resHubVnet.id +output outHubVirtualNetworkIdSecondaryLocation string = resHubVnetSecondaryLocation.id + +output outHubRouteTableId string = parAzFirewallEnabled ? resHubRouteTable.id : '' +output outHubRouteTableIdSecondaryLocation string = parAzFirewallEnabledSecondaryLocation ? resHubRouteTableSecondaryLocation.id : '' + +output outHubRouteTableName string = parAzFirewallEnabled ? resHubRouteTable.name : '' +output outHubRouteTableNameSecondaryLocation string = parAzFirewallEnabledSecondaryLocation ? resHubRouteTableSecondaryLocation.name : '' + +output outBastionNsgId string = parAzBastionEnabled ? resBastionNsg.id : '' +output outBastionNsgIdSecondaryLocation string = parAzBastionEnabledSecondaryLocation ? resBastionNsgSecondaryLocation.id : '' + +output outBastionNsgName string = parAzBastionEnabled ? resBastionNsg.name : '' +output outBastionNsgNameSecondaryLocation string = parAzBastionEnabledSecondaryLocation ? resBastionNsgSecondaryLocation.name : '' + diff --git a/infra-as-code/bicep/modules/hubNetworking/parameters/hubNetworking.parameters.az.multiRegion.all.json b/infra-as-code/bicep/modules/hubNetworking/parameters/hubNetworking.parameters.az.multiRegion.all.json new file mode 100644 index 000000000..685c833f9 --- /dev/null +++ b/infra-as-code/bicep/modules/hubNetworking/parameters/hubNetworking.parameters.az.multiRegion.all.json @@ -0,0 +1,475 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "parLocation": { + "value": "eastus" + }, + "parSecondaryLocation": { + "value": "eastus2" + }, + "parCompanyPrefix": { + "value": "alz" + }, + "parHubNetworkName": { + "value": "alz-hub-eastus" + }, + "parHubNetworkNameSecondaryLocation": { + "value": "alz-hub-eastus2" + }, + "parHubNetworkAddressPrefix": { + "value": "10.20.0.0/16" + }, + "parHubNetworkAddressPrefixSecondaryLocation": { + "value": "10.30.0.0/16" + }, + "parSubnets": { + "value": [ + { + "name": "AzureBastionSubnet", + "ipAddressRange": "10.20.0.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "GatewaySubnet", + "ipAddressRange": "10.20.254.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallSubnet", + "ipAddressRange": "10.20.255.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallManagementSubnet", + "ipAddressRange": "10.20.253.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + } + ] + }, + "parSubnetsSecondaryLocation": { + "value": [ + { + "name": "AzureBastionSubnet", + "ipAddressRange": "10.30.0.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "GatewaySubnet", + "ipAddressRange": "10.30.254.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallSubnet", + "ipAddressRange": "10.30.255.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + }, + { + "name": "AzureFirewallManagementSubnet", + "ipAddressRange": "10.30.253.0/24", + "networkSecurityGroupId": "", + "routeTableId": "" + } + ] + }, + "parDnsServerIps": { + "value": [] + }, + "parDnsServerIpsSecondaryLocation": { + "value": [] + }, + "parPublicIpSku": { + "value": "Standard" + }, + "parPublicIpPrefix": { + "value": "" + }, + "parPublicIpPrefixSecondaryLocation": { + "value": "" + }, + "parPublicIpSuffix": { + "value": "-PublicIP" + }, + "parAzBastionEnabled": { + "value": true + }, + "parAzBastionEnabledSecondaryLocation": { + "value": false + }, + "parAzBastionName": { + "value": "alz-bastion-eastus" + }, + "parAzBastionNameSecondaryLocation": { + "value": "alz-bastion-eastus2" + }, + "parAzBastionSku": { + "value": "Standard" + }, + "parAzBastionSkuSecondaryLocation": { + "value": "Standard" + }, + "parAzBastionTunneling": { + "value": false + }, + "parAzBastionTunnelingSecondaryLocation": { + "value": false + }, + "parAzBastionNsgName": { + "value": "nsg-AzureBastionSubnet-eastus" + }, + "parAzBastionNsgNameSecondaryLocation": { + "value": "nsg-AzureBastionSubnet-eastus2" + }, + "parDdosEnabled": { + "value": true + }, + "parDdosPlanName": { + "value": "alz-ddos-plan-eastus" + }, + "parDdosEnabledSecondaryLocation": { + "value": true + }, + "parDdosPlanNameSecondaryLocation": { + "value": "alz-ddos-plan-eastus2" + }, + "parAzFirewallEnabled": { + "value": true + }, + "parAzFirewallName": { + "value": "alz-azfw-eastus" + }, + "parAzFirewallPoliciesName": { + "value": "alz-azfwpolicy-eastus" + }, + "parAzFirewallTier": { + "value": "Standard" + }, + "parAzFirewallIntelMode": { + "value": "Alert" + }, + "parAzFirewallAvailabilityZones": { + "value": [ + "1", + "2", + "3" + ] + }, + "parAzFirewallEnabledSecondaryLocation": { + "value": true + }, + "parAzFirewallNameSecondaryLocation": { + "value": "alz-azfw-eastus2" + }, + "parAzFirewallPoliciesNameSecondaryLocation": { + "value": "alz-azfwpolicy-eastus2" + }, + "parAzFirewallTierSecondaryLocation": { + "value": "Standard" + }, + "parAzFirewallIntelModeSecondaryLocation": { + "value": "Alert" + }, + "parAzFirewallAvailabilityZonesSecondaryLocation": { + "value": [ + "1", + "2", + "3" + ] + }, + "parAzErGatewayAvailabilityZones": { + "value": [ + "1", + "2", + "3" + ] + }, + "parAzVpnGatewayAvailabilityZones": { + "value": [ + "1", + "2", + "3" + ] + }, + "parAzErGatewayAvailabilityZonesSecondaryLocation": { + "value": [ + "1", + "2", + "3" + ] + }, + "parAzVpnGatewayAvailabilityZonesSecondaryLocation": { + "value": [ + "1", + "2", + "3" + ] + }, + "parAzFirewallDnsProxyEnabled": { + "value": true + }, + "parAzFirewallDnsServers": { + "value": [] + }, + "parHubRouteTableNameSecondaryLocation": { + "value": "alz-hub-routetable-eastus2" + }, + "parDisableBgpRoutePropagationSecondaryLocation": { + "value": false + }, + "parAzFirewallDnsProxyEnabledSecondaryLocation": { + "value": true + }, + "parAzFirewallDnsServersSecondaryLocation": { + "value": [] + }, + "parHubRouteTableName": { + "value": "alz-hub-routetable-eastus" + }, + "parDisableBgpRoutePropagation": { + "value": false + }, + "parPrivateDnsZonesEnabled": { + "value": true + }, + "parPrivateDnsZones": { + "value": [ + "privatelink.xxxxxx.azmk8s.io", // Replace xxxxxx with target region (i.e. eastus) + "privatelink.xxxxxx.batch.azure.com", // Replace xxxxxx with target region (i.e. eastus) + "privatelink.xxxxxx.kusto.windows.net", // Replace xxxxxx with target region (i.e. eastus) + "privatelink.xxxxxx.backup.windowsazure.com", // Replace xxxxxx with target region geo code (i.e. for eastus, the geo code is eus) + "privatelink.adf.azure.com", + "privatelink.afs.azure.net", + "privatelink.agentsvc.azure-automation.net", + "privatelink.analysis.windows.net", + "privatelink.api.azureml.ms", + "privatelink.azconfig.io", + "privatelink.azure-api.net", + "privatelink.azure-automation.net", + "privatelink.azurecr.io", + "privatelink.azure-devices.net", + "privatelink.azure-devices-provisioning.net", + "privatelink.azuredatabricks.net", + "privatelink.azurehdinsight.net", + "privatelink.azurehealthcareapis.com", + "privatelink.azurestaticapps.net", + "privatelink.azuresynapse.net", + "privatelink.azurewebsites.net", + "privatelink.batch.azure.com", + "privatelink.blob.core.windows.net", + "privatelink.cassandra.cosmos.azure.com", + "privatelink.cognitiveservices.azure.com", + "privatelink.database.windows.net", + "privatelink.datafactory.azure.net", + "privatelink.dev.azuresynapse.net", + "privatelink.dfs.core.windows.net", + "privatelink.dicom.azurehealthcareapis.com", + "privatelink.digitaltwins.azure.net", + "privatelink.directline.botframework.com", + "privatelink.documents.azure.com", + "privatelink.eventgrid.azure.net", + "privatelink.file.core.windows.net", + "privatelink.gremlin.cosmos.azure.com", + "privatelink.guestconfiguration.azure.com", + "privatelink.his.arc.azure.com", + "privatelink.dp.kubernetesconfiguration.azure.com", + "privatelink.managedhsm.azure.net", + "privatelink.mariadb.database.azure.com", + "privatelink.media.azure.net", + "privatelink.mongo.cosmos.azure.com", + "privatelink.monitor.azure.com", + "privatelink.mysql.database.azure.com", + "privatelink.notebooks.azure.net", + "privatelink.ods.opinsights.azure.com", + "privatelink.oms.opinsights.azure.com", + "privatelink.pbidedicated.windows.net", + "privatelink.postgres.database.azure.com", + "privatelink.prod.migration.windowsazure.com", + "privatelink.purview.azure.com", + "privatelink.purviewstudio.azure.com", + "privatelink.queue.core.windows.net", + "privatelink.redis.cache.windows.net", + "privatelink.redisenterprise.cache.azure.net", + "privatelink.search.windows.net", + "privatelink.service.signalr.net", + "privatelink.servicebus.windows.net", + "privatelink.siterecovery.windowsazure.com", + "privatelink.sql.azuresynapse.net", + "privatelink.table.core.windows.net", + "privatelink.table.cosmos.azure.com", + "privatelink.tip1.powerquery.microsoft.com", + "privatelink.token.botframework.com", + "privatelink.vaultcore.azure.net", + "privatelink.web.core.windows.net", + "privatelink.webpubsub.azure.com" + ] + }, + "parPrivateDnsZoneAutoMergeAzureBackupZone": { + "value": true + }, + "parVpnGatewayEnabled": { + "value": true + }, + "parVpnGatewayEnabledSecondaryLocation": { + "value": true + }, + "parVpnGatewayConfig": { + "value": { + "name": "alz-vpn-gateway", + "gatewayType": "Vpn", + "sku": "VpnGw1AZ", + "vpnType": "RouteBased", + "generation": "Generation1", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": "65515", + "bgpPeeringAddress": "", + "peerWeight": "5" + }, + "vpnClientConfiguration": {} + } + }, + "parVpnGatewayConfigSecondaryLocation": { + "value": { + "name": "alz-vpn-gateway-secondary", + "gatewayType": "Vpn", + "sku": "VpnGw1AZ", + "vpnType": "RouteBased", + "generation": "Generation1", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": "65515", + "bgpPeeringAddress": "", + "peerWeight": "5" + }, + "vpnClientConfiguration": {} + } + }, + "parExpressRouteGatewayEnabled": { + "value": true + }, + "parExpressRouteGatewayConfig": { + "value": { + "name": "alz-expressroute-gateway", + "gatewayType": "ExpressRoute", + "sku": "ErGw1Az", + "vpnType": "RouteBased", + "generation": "None", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": "65515", + "bgpPeeringAddress": "", + "peerWeight": "5" + } + } + }, + "parExpressRouteGatewayEnabledSecondaryLocation": { + "value": true + }, + "parExpressRouteGatewayConfigSecondaryLocation": { + "value": { + "name": "alz-expressroute-gateway-secondary", + "gatewayType": "ExpressRoute", + "sku": "ErGw1Az", + "vpnType": "RouteBased", + "generation": "None", + "enableBgp": false, + "activeActive": false, + "enableBgpRouteTranslationForNat": false, + "enableDnsForwarding": false, + "bgpPeeringAddress": "", + "bgpsettings": { + "asn": "65515", + "bgpPeeringAddress": "", + "peerWeight": "5" + } + } + }, + "parTags": { + "value": { + "Environment": "Live" + } + }, + "parTelemetryOptOut": { + "value": false + }, + "parBastionOutboundSshRdpPorts": { + "value": [ + "22", + "3389" + ] + }, + "parBastionOutboundSshRdpPortsSecondaryLocation": { + "value": [ + "22", + "3389" + ] + }, + "parGlobalResourceLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parVirtualNetworkLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parBastionLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parDdosLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parAzureFirewallLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parHubRouteTableLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parPrivateDNSZonesLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + }, + "parVirtualNetworkGatewayLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep Hub Networking Module." + } + } + } +} diff --git a/infra-as-code/bicep/modules/vwanConnectivity/parameters/vwanConnectivity.parameters.az.multiRegion.all.json b/infra-as-code/bicep/modules/vwanConnectivity/parameters/vwanConnectivity.parameters.az.multiRegion.all.json new file mode 100644 index 000000000..976085211 --- /dev/null +++ b/infra-as-code/bicep/modules/vwanConnectivity/parameters/vwanConnectivity.parameters.az.multiRegion.all.json @@ -0,0 +1,230 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "parLocation": { + "value": "eastus" + }, + "parCompanyPrefix": { + "value": "alz" + }, + "parVirtualHubEnabled": { + "value": true + }, + "parVirtualWanName": { + "value": "alz-vwan" + }, + "parVirtualWanHubName": { + "value": "alz-vhub" + }, + "parVirtualWanHubDefaultRouteName": { + "value": "default-to-azfw" + }, + "parVpnGatewayName": { + "value": "alz-vpngw" + }, + "parExpressRouteGatewayName": { + "value": "alz-ergw" + }, + "parAzFirewallName": { + "value": "alz-fw" + }, + "parAzFirewallPoliciesName": { + "value": "alz-azfwpolicy" + }, + "parVirtualWanHubs": { + "value": [ + { + "parVpnGatewayEnabled": true, + "parExpressRouteGatewayEnabled": true, + "parAzFirewallEnabled": true, + "parVirtualHubAddressPrefix": "10.100.0.0/23", + "parHubLocation": "eastus", + "parHubRoutingPreference": "ExpressRoute", + "parVirtualRouterAutoScaleConfiguration": 2, + "parVirtualHubRoutingIntentDestinations": [], + "parAzFirewallDnsServers": [], + "parAzFirewallIntelMode": "Alert", + "parAzFirewallDnsProxyEnabled": true, + "parAzFirewallTier": "Standard", + "parAzFirewallAvailabilityZones": [ + "1", + "2", + "3" + ] + }, + { + "parVpnGatewayEnabled": true, + "parExpressRouteGatewayEnabled": true, + "parAzFirewallEnabled": true, + "parVirtualHubAddressPrefix": "10.200.0.0/23", + "parHubLocation": "westus2", + "parHubRoutingPreference": "ExpressRoute", + "parVirtualRouterAutoScaleConfiguration": 2, + "parVirtualHubRoutingIntentDestinations": [], + "parAzFirewallDnsServers": [], + "parAzFirewallIntelMode": "Alert", + "parAzFirewallDnsProxyEnabled": true, + "parAzFirewallTier": "Standard", + "parAzFirewallAvailabilityZones": [ + "1", + "2", + "3" + ] + } + ] + }, + "parVpnGatewayScaleUnit": { + "value": 1 + }, + "parExpressRouteGatewayScaleUnit": { + "value": 1 + }, + "parDdosEnabled": { + "value": false + }, + "parDdosPlanName": { + "value": "alz-ddos-plan" + }, + "parPrivateDnsZonesEnabled": { + "value": true + }, + "parPrivateDnsZones": { + "value": [ + "privatelink.westus.azmk8s.io", // Replace xxxxxx with target region (i.e. eastus) + "privatelink.westus.batch.azure.com", // Replace xxxxxx with target region (i.e. eastus) + "privatelink.westus.kusto.windows.net", // Replace xxxxxx with target region (i.e. eastus) + "privatelink.westus.backup.windowsazure.com", // Replace xxxxxx with target region geo code (i.e. for eastus, the geo code is eus) + "privatelink.adf.azure.com", + "privatelink.afs.azure.net", + "privatelink.agentsvc.azure-automation.net", + "privatelink.analysis.windows.net", + "privatelink.api.azureml.ms", + "privatelink.azconfig.io", + "privatelink.azure-api.net", + "privatelink.azure-automation.net", + "privatelink.azurecr.io", + "privatelink.azure-devices.net", + "privatelink.azure-devices-provisioning.net", + "privatelink.azuredatabricks.net", + "privatelink.azurehdinsight.net", + "privatelink.azurehealthcareapis.com", + "privatelink.azurestaticapps.net", + "privatelink.azuresynapse.net", + "privatelink.azurewebsites.net", + "privatelink.batch.azure.com", + "privatelink.blob.core.windows.net", + "privatelink.cassandra.cosmos.azure.com", + "privatelink.cognitiveservices.azure.com", + "privatelink.database.windows.net", + "privatelink.datafactory.azure.net", + "privatelink.dev.azuresynapse.net", + "privatelink.dfs.core.windows.net", + "privatelink.dicom.azurehealthcareapis.com", + "privatelink.digitaltwins.azure.net", + "privatelink.directline.botframework.com", + "privatelink.documents.azure.com", + "privatelink.eventgrid.azure.net", + "privatelink.file.core.windows.net", + "privatelink.gremlin.cosmos.azure.com", + "privatelink.guestconfiguration.azure.com", + "privatelink.his.arc.azure.com", + "privatelink.dp.kubernetesconfiguration.azure.com", + "privatelink.managedhsm.azure.net", + "privatelink.mariadb.database.azure.com", + "privatelink.media.azure.net", + "privatelink.mongo.cosmos.azure.com", + "privatelink.monitor.azure.com", + "privatelink.mysql.database.azure.com", + "privatelink.notebooks.azure.net", + "privatelink.ods.opinsights.azure.com", + "privatelink.oms.opinsights.azure.com", + "privatelink.pbidedicated.windows.net", + "privatelink.postgres.database.azure.com", + "privatelink.prod.migration.windowsazure.com", + "privatelink.purview.azure.com", + "privatelink.purviewstudio.azure.com", + "privatelink.queue.core.windows.net", + "privatelink.redis.cache.windows.net", + "privatelink.redisenterprise.cache.azure.net", + "privatelink.search.windows.net", + "privatelink.service.signalr.net", + "privatelink.servicebus.windows.net", + "privatelink.siterecovery.windowsazure.com", + "privatelink.sql.azuresynapse.net", + "privatelink.table.core.windows.net", + "privatelink.table.cosmos.azure.com", + "privatelink.tip1.powerquery.microsoft.com", + "privatelink.token.botframework.com", + "privatelink.vaultcore.azure.net", + "privatelink.web.core.windows.net", + "privatelink.webpubsub.azure.com" + ] + }, + "parPrivateDnsZoneAutoMergeAzureBackupZone": { + "value": true + }, + "parVirtualNetworkIdToLink": { + "value": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/HUB_Networking_POC/providers/Microsoft.Network/virtualNetworks/alz-hub-eastus" + }, + "parTags": { + "value": { + "Environment": "Live" + } + }, + "parVirtualNetworkIdToLinkFailover": { + "value": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/HUB_Networking_POC/providers/Microsoft.Network/virtualNetworks/alz-hub-eastus-failover" + }, + "parTelemetryOptOut": { + "value": false + }, + "parGlobalResourceLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parVirtualWanLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parVirtualWanHubsLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parDdosLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parAzureFirewallLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parVpnGatewayLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parPrivateDNSZonesLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + }, + "parExpressRouteGatewayLock": { + "value": { + "kind": "None", + "notes": "This lock was created by the ALZ Bicep vWAN Connectivity Module." + } + } + } +}