Azure Virtual Network provides a logical, isolated and secure network boundary inside Azure. As more and more workloads start to get deployed in Azure Virtual Networks, enabling network connectivity across them starts to become challenging. There are multiple options to address these challenges. These options include Virtual Network (VNet) Peering, using VPN gateway between 2 virtual networks, etc.
To address common VNet connectivity challenges, a pattern has evolved over the years. This pattern is referred as "Hub and spoke" network topology in Azure.
Hub and spoke network topology pattern bring multiple benefits and simplifies network connectivity in Azure. Azure has another service called as Azure Virtual WAN (vWAN). Azure vWAN provides *managed hub and spoke topology* facilitating any-to-any connectivity.
This post will compare and contrast Hub and spoke network topology and Azure vWAN to help customers make informed decision.
Scenario
This post will evaluate Hub and spoke network topology and Azure vWAN using a scenario with 2 workflow as depicted below.
Each workflow is described at a high-level as below.
Hub VNet workflow:
vWAN hub workflow:
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[parameters('hubVnetName')]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('hubVnetAddressPrefix')]"
]
}
"subnets": [
{
"name": "GatewaySubnet",
"properties": {
"addressPrefix": "[parameters('gatewaySubnetPrefix')]"
}
}
]
# Create a self-signed root certificate
$rootcert = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject "CN=makshP2SRootCert" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign
# Generate a client certificate
$clientCert = New-SelfSignedCertificate -Type Custom -DnsName makshP2SChildCert -KeySpec Signature `
-Subject "CN=makshP2SChildCert" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My" `
-Signer $rootcert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2")
# Export client certificate
$myclientpwd = ConvertTo-SecureString -String "<super-secret-password>" -Force -AsPlainText
Export-PfxCertificate -Password $myclientpwd -Cert (get-item -Path Cert:\CurrentUser\My\$($clientCert.Thumbprint)) -FilePath myp2svpnclientCert.pfx
# Get Base64 encoded raw certificate data to be used in ARM Template
$([Convert]::ToBase64String($rootcert.Export('Cert')))
"clientRootCertData": {
"value": "<base64-encoded-raw-certificate-data-obtained-above>"
}
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[parameters('gatewayPublicIPName')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic"
}
}
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworkGateways",
"name": "[parameters('gatewayName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
...
]
}
"ipConfigurations": [
{
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('gatewaySubnetRef')]"
},
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',parameters('gatewayPublicIPName'))]"
}
},
"name": "vnetGatewayConfig"
}
]
"vpnClientConfiguration": {
"vpnClientAddressPool": {
"addressPrefixes": [
"[parameters('vpnClientAddressPoolPrefix')]"
]
},
"vpnClientRootCertificates": [
{
"name": "[parameters('clientRootCertName')]",
"properties": {
"PublicCertData": "[parameters('clientRootCertData')]"
}
}
]
}
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[parameters('spoke1VnetName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
...
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('spoke1VnetAddressPrefix')]"
]
},
}
"subnets": [
{
"name": "default",
"properties": {
"addressPrefix": "[parameters('spoke1SubnetAddressPrefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', 'spoke-vnet1-subnet-nsg')]"
}
}
}
]
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('spoke1Vm1Name')]",
"location": "[resourceGroup().location]",
"dependsOn": [
...
],
"properties": {
"hardwareProfile": {
"vmSize": "Standard_A2_v2"
},
"osProfile": {
"computerName": "[parameters('spoke1Vm1Name')]",
"adminUsername": "spoke1vm1-uid",
"adminPassword": "<super-secret-password>"
},
"storageProfile": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2012-R2-Datacenter",
"version": "latest"
},
"osDisk": {
"name": "[concat(parameters('spoke1Vm1Name'),'_OSDisk')]",
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('vm1-spoke1-nic'))]"
}
]
}
}
}
{
"apiVersion": "2020-05-01",
"type": "virtualNetworkPeerings",
"name": "[variables('SpokevNet1toHubvNetPeeringName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
...
],
"comments": "Peering from Spoke vNet 1 to Hub vNet",
"properties": {
"allowVirtualNetworkAccess": true,
"allowForwardedTraffic": false,
"allowGatewayTransit": false,
"useRemoteGateways": true,
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks',parameters('hubVnetName'))]"
}
}
}
{
"apiVersion": "2020-05-01",
"type": "virtualNetworkPeerings",
"name": "[variables('HubvNettoSpokevNet1PeeringName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
...
],
"comments": "Peering from Hub vNet to Spoke vNet 1",
"properties": {
"allowVirtualNetworkAccess": true,
"allowForwardedTraffic": false,
"allowGatewayTransit": true,
"useRemoteGateways": false,
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks',parameters('spoke1VnetName'))]"
}
}
}
az network vnet-gateway vpn-client generate -n hubvnetGateway `
--processor-architecture Amd64 `
-g $rgName
{
"type": "Microsoft.Network/virtualWans",
"name": "[parameters('vwanName')]",
"apiVersion": "2020-05-01",
"location": "[resourceGroup().location]",
"properties": {
"allowVnetToVnetTraffic": true,
"type": "Standard"
}
}
{
"type": "Microsoft.Network/virtualHubs",
"name": "[parameters('vWanHubName')]",
"apiVersion": "2020-04-01",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualWans/', parameters('vwanName'))]",
...
]
}
{
"type": "Microsoft.Network/vpnServerConfigurations",
"apiVersion": "2020-05-01",
"name": "vwan-p2s-vpn-config",
"location": "[resourceGroup().location]",
"properties": {
"vpnProtocols": [
"IkeV2"
],
"vpnAuthenticationTypes": [
"Certificate"
],
"vpnClientRootCertificates": [
{
"name": "[parameters('clientRootCertName')]",
"publicCertData": "[parameters('clientRootCertData')]"
}
],
...
}
}
{
"type": "Microsoft.Network/virtualHubs/hubRouteTables",
"apiVersion": "2020-05-01",
"name": "[concat(parameters('vWanHubName'), '/defaultRouteTable')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualHubs', parameters('vWanHubName'))]"
]
...
}
{
"type": "Microsoft.Network/p2sVpnGateways",
"apiVersion": "2020-05-01",
"name": "[parameters('vwanP2SVpnGatewayName')]",
"location": "uksouth",
"dependsOn": [
...
],
"properties": {
"virtualHub": {
"id": "[resourceId('Microsoft.Network/virtualHubs', parameters('vWanHubName'))]"
},
"vpnServerConfiguration": {
"id": "[resourceId('Microsoft.Network/vpnServerConfigurations', 'vwan-p2s-vpn-config')]"
},
...
"vpnClientAddressPool": {
"addressPrefixes": [
"10.10.8.0/24"
]
}
}
}
{
"type": "Microsoft.Network/virtualHubs",
"name": "[parameters('vWanHubName')]",
"apiVersion": "2020-04-01",
"location": "[resourceGroup().location]",
"dependsOn": [
...
],
"properties": {
...
},
"p2SVpnGateway": {
"id": "[resourceId('Microsoft.Network/p2sVpnGateways', parameters('vwanP2SVpnGatewayName'))]"
},
...
}
{
"type": "Microsoft.Network/virtualHubs",
"name": "[parameters('vWanHubName')]",
"apiVersion": "2020-04-01",
"location": "[resourceGroup().location]",
"dependsOn": [
...
],
"properties": {
...
"virtualNetworkConnections": [
{
"name": "vhub-to-web-server-vnet",
"properties": {
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('spoke3VnetName'))]"
},
"allowHubToRemoteVnetTransit": true,
"allowRemoteVnetToUseHubVnetGateways": true,
"enableInternetSecurity": true
}
},
{
"name": "vhub-to-database-server-vnet",
"properties": {
"remoteVirtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('spoke4VnetName'))]"
},
"allowHubToRemoteVnetTransit": true,
"allowRemoteVnetToUseHubVnetGateways": true,
"enableInternetSecurity": true
}
}
],
"sku": "Standard"
}
}
{
"type": "Microsoft.Network/virtualHubs/hubRouteTables",
"apiVersion": "2020-05-01",
"name": "[concat(parameters('vWanHubName'), '/defaultRouteTable')]",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualHubs', parameters('vWanHubName'))]"
],
"properties": {
"routes": [
{
"name": "spoke3route",
"destinationType": "CIDR",
"destinations": [
"192.168.251.0/24"
],
"nextHopType": "ResourceId",
"nextHop": "[resourceId('Microsoft.Network/virtualHubs/hubVirtualNetworkConnections', parameters('vWanHubName'), 'vhub-to-spoke3')]"
},
{
"name": "spoke4route",
"destinationType": "CIDR",
"destinations": [
"192.168.252.0/24"
],
"nextHopType": "ResourceId",
"nextHop": "[resourceId('Microsoft.Network/virtualHubs/hubVirtualNetworkConnections', parameters('vWanHubName'), 'vhub-to-spoke4')]"
}
],
"labels": [
"default"
]
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.