Deploying an Azure Hub-Spoke Network using Bicep: A simple Infrastructure-as-Code example.
Infrastructure as Code is becoming an essential practice for cloud engineers and architects.
When working with Microsoft Azure, Bicep provides a powerful and elegant way to define infrastructure using code instead of manual configuration in the Azure portal.
Bicep is a domain-specific language developed by Microsoft for Azure Resource Manager deployments. It simplifies ARM templates while keeping full compatibility with Azure services.
Compared to traditional ARM templates written in JSON, Bicep offers several advantages:
• cleaner syntax
• better readability
• easier maintenance
• native integration with Azure deployments
Example: Deploying a Hub-Spoke network architecture
In this example, a simple Hub-Spoke network architecture was deployed using a single Bicep template.
The deployment creates the following components:
• Hub Virtual Network
The hub network acts as the central connectivity layer where shared services are hosted.
• VPN Gateway
The Virtual Network Gateway enables secure connectivity between Azure and external networks such as on-premises environments using VPN tunnels.
• Spoke Virtual Networks
Two spoke VNets are deployed:
VNet A VNet B
These networks represent application or workload environments connected to the hub using VNet Peering.
• User Defined Route (UDR)
A route table is associated with VNet A to direct traffic toward a Network Virtual Appliance (NVA) located in the hub network.
This allows centralized routing and traffic inspection scenarios.
Infrastructure deployed in minutes
With Bicep, the entire architecture can be deployed in minutes using a single command.
Recommended by LinkedIn
Instead of manually configuring resources in the Azure portal, the infrastructure becomes:
• repeatable
• version-controlled
• easier to maintain
• easier to reproduce across environments
On your Resource Group by clicking the Resource Visualizer, you will see something like this:
Here is the Bicep file:
/*
AZURE HUB & SPOKE ARCHITECTURE
- Hub VNet: 10.3.0.0/16 with VPN Gateway & NVA
- Spoke A: 10.1.0.0/16 with UDR to NVA
- Spoke B: 10.2.0.0/16 with Remote Gateway Transit
*/
param location string = resourceGroup().location
param nvaIpAddress string = '10.3.1.4' // Target IP for the Network Virtual Appliance
// --- HUB VIRTUAL NETWORK ---
resource hubVnet 'Microsoft.Network/virtualNetworks@2024-01-01' = {
name: 'Hub-VNet'
location: location
properties: {
addressSpace: {
addressPrefixes: ['10.3.0.0/16']
}
subnets: [
{
name: 'NVA-Subnet'
properties: {
addressPrefix: '10.3.1.0/24'
}
}
{
name: 'GatewaySubnet' // Required name for VPN Gateway
properties: {
addressPrefix: '10.3.255.0/27'
}
}
]
}
}
// --- SPOKE VNET A (UDR Implementation) ---
resource vnetA 'Microsoft.Network/virtualNetworks@2024-01-01' = {
name: 'VNet-A'
location: location
properties: {
addressSpace: {
addressPrefixes: ['10.1.0.0/16']
}
subnets: [
{
name: 'Workload-Subnet'
properties: {
addressPrefix: '10.1.1.0/24'
routeTable: {
id: routeTableA.id
}
}
}
]
}
}
// --- SPOKE VNET B (Remote Gateway Implementation) ---
resource vnetB 'Microsoft.Network/virtualNetworks@2024-01-01' = {
name: 'VNet-B'
location: location
properties: {
addressSpace: {
addressPrefixes: ['10.2.0.0/16']
}
subnets: [
{
name: 'Workload-Subnet'
properties: {
addressPrefix: '10.2.1.0/24'
}
}
]
}
}
// --- ROUTE TABLE FOR VNET A (Force traffic to NVA) ---
resource routeTableA 'Microsoft.Network/routeTables@2024-01-01' = {
name: 'RT-VNetA-to-NVA'
location: location
properties: {
routes: [
{
name: 'To-Hub-via-NVA'
properties: {
addressPrefix: '10.3.0.0/16'
nextHopType: 'VirtualAppliance'
nextHopIpAddress: nvaIpAddress
}
}
]
}
}
// --- VPN GATEWAY (For On-premises connectivity) ---
resource publicIp 'Microsoft.Network/publicIPAddresses@2024-01-01' = {
name: 'VPN-Gateway-PIP'
location: location
sku: { name: 'Standard' }
properties: {
publicIPAllocationMethod: 'Static'
}
}
resource vpnGateway 'Microsoft.Network/virtualNetworkGateways@2024-01-01' = {
name: 'Hub-VPN-Gateway'
location: location
properties: {
ipConfigurations: [
{
name: 'vnetGatewayConfig'
properties: {
publicIPAddress: { id: publicIp.id }
subnet: { id: '${hubVnet.id}/subnets/GatewaySubnet' }
}
}
]
gatewayType: 'Vpn'
vpnType: 'RouteBased'
sku: { name: 'VpnGw1', tier: 'VpnGw1' }
}
}
// --- PEERING: HUB <-> VNET A ---
resource hubToA 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2024-01-01' = {
parent: hubVnet
name: 'Hub-to-VNetA'
properties: {
remoteVirtualNetwork: { id: vnetA.id }
allowVirtualNetworkAccess: true
allowForwardedTraffic: true
allowGatewayTransit: false
}
}
resource aToHub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2024-01-01' = {
parent: vnetA
name: 'VNetA-to-Hub'
properties: {
remoteVirtualNetwork: { id: hubVnet.id }
allowVirtualNetworkAccess: true
allowForwardedTraffic: true
useRemoteGateways: false
}
}
// --- PEERING: HUB <-> VNET B (With Gateway Transit) ---
resource hubToB 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2024-01-01' = {
parent: hubVnet
name: 'Hub-to-VNetB'
properties: {
remoteVirtualNetwork: { id: vnetB.id }
allowVirtualNetworkAccess: true
allowForwardedTraffic: true
allowGatewayTransit: true // Enabled for Spoke B to use the Hub Gateway
}
}
resource bToHub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2024-01-01' = {
parent: vnetB
name: 'VNetB-to-Hub'
properties: {
remoteVirtualNetwork: { id: hubVnet.id }
allowVirtualNetworkAccess: true
allowForwardedTraffic: true
useRemoteGateways: true // Enabled as per diagram
}
dependsOn: [vpnGateway] // Must wait for Gateway deployment to enable transit
}
Architecture Diagram - Result after deployement
Bicep Visualizer
Target Architecture
This diagram below illustrates the Hub-Spoke network architecture.
It shows a central Hub virtual network containing a VPN Gateway and a dedicated subnet for a Network Virtual Appliance (NVA), connected to two spoke virtual networks through VNet peering. A route table is used to direct traffic from one spoke toward the NVA in the hub.
Commands to deploy the bicep file
az deployment group create \
--resource-group NetPeeringVnetLab \
--template-file hub-spoke-vpn-nva.bicep \
Learn more on: Azure Virtual Network Peering | Microsoft Learn
#Azure #MicrosoftAzure #Bicep #InfrastructureAsCode #CloudArchitecture
Are you currently using Bicep or Terraform for your Azure deployments?
In this article I show how to deploy a simple Azure Hub-Spoke architecture using Bicep. The goal is to demonstrate how Infrastructure as Code can simplify Azure networking deployments.