Nasazení minimální hub-spoke topologie v Azure

18.10.2026

Bicep hub-spoke deployment s routováním přes Linux VM.

Slovník

hub-spoke topologie Doporučená síťová topologie v Azure, kde je centrální síť (hub) propojena s dalšími sítěmi (spokes). Alternativou je Virtual WAN.
Infrastructure as Code (IaC) Automatizované nasazování a správa infrastruktury pomocí kódu.
Bicep Nativní deklarativní jazyk pro nasazování infrastruktury v Azure. Bicep je nadstavba nad Azure Resource Manager (ARM) šablonami.
Azure Verified Modules (AVM) Bicep a Terraform moduly v rámci iniciativy Microsoftu, která se zaměřuje na standardizaci IaC kódu.
Subscription Subskripce je prostor, do kterého se nasazuje infrastruktura a aplikace. V architektuře Azure landing zone s hub-spoke topologií je obvykle vyhrazená pro konkrétní systém a prostředí.
Virtual Network (VNet) Izolovaná privátní síť s vlastním adresním prostorem, která je dále rozdělená na jednu nebo více podsítí.
Subnet Podsíť v rámci VNetu s přiřazeným rozsahem adres. Některé služby, jako například Azure Firewall nebo VPN Gateway, vyžadují vyhrazenou podsíť.
Virtual Network Peering Propojení dvou virtuálních sítí (VNet) v rámci jedné subskripce, mezi subskripcemi i mezi regiony. Peering umožňuje komunikaci pomocí privátních IP adres po páteřní síti Microsoftu. Není tranzitivní, takže spoke sítě spolu v hub-spoke topologii komunikují přes hub, kde provoz směruje některá ze služeb s funkcí routeru (např. Azure Firewall nebo NVA).
Síťová tranzitivita Vlastnost propojení sítí, kdy spojení sítě A se sítí B a sítě B se sítí C automaticky umožňuje komunikaci mezi sítí A a sítí C.
Network Virtual Appliance (NVA) Virtuální server (VM), který v síti plní roli síťového zařízení, například routeru, firewallu nebo VPN gateway.
Virtual Machine (VM) Virtuální server.
Azure Accelerated Networking Funkce síťového rozhraní (NIC) virtuálního serveru (VM), která pomocí technologie SR-IOV (Single Root I/O Virtualization) posílá síťový provoz přímo do VM a obchází virtuální switch hostitele. Snižuje latenci, jitter a zátěž CPU a zvyšuje propustnost. Podporují ji jen vybrané velikosti VM a operační systémy.

Obsah

Úvod

Hub-spoke topologie je doporučená síťová topologie v Azure, kterou si nasadíme pomocí Bicep kódu (s AVM moduly) tak, abychom měli centrální hub síť a dvě spoke sítě, které budou s hubem propojeny přes VNet peering. Pro směrování provozu mezi spoke sítěmi využijeme Linux VM, který bude fungovat jako router.

Adresní prostory jsou nastaveny jako příklad, nesmí se překrývat a je nutné si je zvolit podle potřeby a reálného use-case. Azure si v každé podsíti rezervuje pět IP adres, které nelze přiřadit. Patří mezi ně první čtyři adresy a poslední adresa v rozsahu dané podsítě. Praktické tipy, jak správně zvolit rozsahy lze najít zde:

VNet/Subnet Adresní prostor Rozsah Počet adres
Connectivity VNet (hub) 10.0.0.0/22 10.0.0.1 - 10.0.3.254 1022
Connectivity Subnet (hub) 10.0.0.0/24 10.0.0.1 - 10.0.0.254 254
App1-dev VNet (spoke) 10.0.4.0/22 10.0.4.1 - 10.0.7.254 1022
App1-dev Subnet (spoke) 10.0.4.0/24 10.0.4.1 - 10.0.4.254 254
App2-dev VNet (spoke) 10.0.8.0/22 10.0.8.1 - 10.0.11.254 1022
App2-dev Subnet (spoke) 10.0.8.0/24 10.0.8.1 - 10.0.8.254 254

Příprava lokálního prostředí

Nainstalujeme si Azure CLI a Bicep CLI. Vše spouštíme přes PowerShell.
winget install --exact --id Microsoft.AzureCLI 
az bicep upgrade
Bicep soubory jsem nahrál do dedikovaného repository a pokud by článek byl příliš popisný, tak je možné postupovat i podle instrukcí v README. Stáhneme soubory:
git clone https://github.com/Ninjanaut/azure-hub-spoke-bicep-template-01.git
cd azure-hub-spoke-bicep-template-0
repository obsahuje dvě hlavní složky, platform a landing-zones.
platform/
├── hub.bicep 
└── connectivity/
    ├── params/
    │   └── shared.bicepparam
    ├── main.bicep
    └── router-cloud.init.yaml
landing-zones/
├── app1/
│   └── dev.bicepparam
├── app2/
│   └── dev.bicepparam
└── main.bicep

Před nasazením je potřeba nastavit parametry, jako například region nebo VM sizing. Přednastavil jsem nejlevnější dostupný sizing, ale je potřeba dostupnost před spuštěním zkontrolovat. Adresářovou strukturu, jmennou konvenci a single repository jsem zvolil pro potřeby příkladu a je vhodné si setup přizpůsobit pro enterprise potřeby, podle rozdělení zodpovědností v týmech, oprávnění a nastavení DevOps pipeliny. Předpokládá se, že uživatel má roli Owner nebo Contributor u subskripce, kterou nasazuje. U nasazování spoke (aplikace 1 a 2) je potřeba mít oprávnění nejen na spoke subskripci, ale i na nastavení hub VNet peeringu (např. Network Contributor).

Základní příkazy pro práci s Bicep soubory jsou az bicep build a az deployment.

az bicep lint
az bicep build
az deployment sub validate
az deployment sub what-if
az deployment sub create

Kompletní dokumentace k Bicep jazyku a toolingu je zde a k az deploymentu zde.

Deployment

Přihlásíme se do Azure portálu a vytvoříme 3 subskripce: Connectivity, app1-dev, app2-dev, resp. dle potřeby. Subskripce musí existovat, protože Bicep šablony je nevytvoří. Následný deployment bude probíhat z lokálního PC (developer machine).

Vygenerování SSH klíče

Vygenerujeme privátní a veřejný klíč, který potřebujeme pro VM provisioning.
ssh-keygen -t ed25519 -f "$HOME\.ssh\azure-hub-spoke-template-01" -C "azure-hub-spoke-template-01"

Připojení do Azure z CLI

V PowerShell terminálu nastavíme a zkontrolujeme ADMIN_SSH_PUBLIC_KEY proměnnou, která bude vstupem do Bicep deploymentu (.bicepparam soubory si ji čtou pomocí readEnvironmentVariable()), a přihlásíme se do Azure.
$env:ADMIN_SSH_PUBLIC_KEY = Get-Content "$HOME\.ssh\azure-hub-spoke-template-01.pub"
$env:ADMIN_SSH_PUBLIC_KEY

az login --tenant '<tenant-id>' # Login
az account set --subscription '<hub-subscription-id>' # Přepnutí do konkrétní subskripce
az account show -o table # Kontrola, ve které subskripci se nacházíme

Nasazení Hubu

Spustíme deployment:
az account set --subscription '<hub-subscription-id>'
az deployment sub create -n hub-shared -l swedencentral -f platform/connectivity/main.bicep -p platform/connectivity/params/shared.bicepparam

V Azure se vytvoří následující resources:

Následně upravíme parametry (primárně subscriptionId) v souboru platform/hub.bicep. Soubor je vstupem do Bicep šablony aplikace 1 a aplikace 2, z důvodu nastavení oboustranného síťového peeringu.

Nasazení aplikace 1

Spustíme deployment:
az account set --subscription '<app1-subscription-id>'
az deployment sub create -n spoke-app1-dev -l swedencentral -f landing-zones/main.bicep -p landing-zones/app1/dev.bicepparam

V Azure se vytvoří následující resources:

Nasazení aplikace 2

Spustíme deployment:
az account set --subscription '<app2-subscription-id>'
az deployment sub create -n spoke-app2-dev -l swedencentral -f landing-zones/main.bicep -p landing-zones/app2/dev.bicepparam

V Azure se vytvoří následující resources:

Kontrola konektivity

V hub VNet zkontrolujeme, že máme nastavený peering na VNet aplikace 1 a VNet aplikace 2.

Routování mezi spoke sítěmi

Protože VNet peering není tranzitivní, spoke sítě na sebe přímo nevidí. Aby provoz mezi aplikací 1 a aplikací 2 fungoval, musí platit tři podmínky:

  1. IP forwarding musí být u Linux VM v hub síti zapnutý na síťové kartě (NIC) a zároveň v operačním systému.
    • V souboru platform/connectivity/main.bicep nastavení enableIPForwarding: true u router modulu.
    • V souboru router-cloud.init.yaml nastavení net.ipv4.ip_forward=1.
  2. Síťový peering mezi hub a spokes musí mít povolený forwarding.
    • V souboru landing-zones/main.bicep nastavení allowForwardedTraffic: true a remotePeeringAllowForwardedTraffic: true u vnet modulu.
  3. Spoke musí mít nastavenou směrovací tabulku (route table) s next hop adresou Linux VM v hubu.
    • V souboru landing-zones/main.bicep nastavení modulu routeTable.

Ping a tracepath mezi aplikacemi

Spustíme ping a tracepath z VM aplikace 1 (10.0.4.4) do VM aplikace 2 (10.0.8.4). Ping je úspěšný a tracepath ukazuje hop přes hub router VM (10.0.0.4).
az vm run-command invoke -g rg-spoke-app1-dev -n vm-conntest-app1-dev-swedencentral-001 --command-id RunShellScript --scripts "ping -c 4 10.0.8.4; tracepath -n 10.0.8.4"
{
  "value": [
    {
      "code": "ProvisioningState/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "Enable succeeded: \n[stdout]\nPING 10.0.8.4 (10.0.8.4) 56(84) bytes of data.\n64 bytes from 10.0.8.4: icmp_seq=1 ttl=63 time=15.4 ms\n64 bytes from 10.0.8.4: icmp_seq=2 ttl=63 time=3.51 ms\n64 bytes from 10.0.8.4: icmp_seq=3 ttl=63 time=2.51 ms\n64 bytes from 10.0.8.4: icmp_seq=4 ttl=63 time=2.75 ms\n\n--- 10.0.8.4 ping statistics ---\n4 packets transmitted, 4 received, 0% packet loss, time 3005ms\nrtt min/avg/max/mdev = 2.512/6.043/15.407/5.418 ms\n 1?: [LOCALHOST]                      pmtu 1500\n 1:  10.0.0.4                                              1.640ms \n 1:  10.0.0.4                                              1.578ms \n 2:  10.0.8.4                                              1.839ms reached\n     Resume: pmtu 1500 hops 2 back 2 \n\n[stderr]\n"
    }
  ]
}
Spustíme ping a tracepath z VM aplikace 2 (10.0.8.4) do VM aplikace 1 (10.0.4.4). Ping je úspěšný a tracepath ukazuje hop přes hub router VM (10.0.0.4).
az vm run-command invoke -g rg-spoke-app2-dev -n vm-conntest-app2-dev-swedencentral-001 --command-id RunShellScript --scripts "ping -c 4 10.0.4.4; tracepath -n 10.0.4.4"
{
  "value": [
    {
      "code": "ProvisioningState/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "Enable succeeded: \n[stdout]\nPING 10.0.4.4 (10.0.4.4) 56(84) bytes of data.\n64 bytes from 10.0.4.4: icmp_seq=1 ttl=63 time=2.86 ms\n64 bytes from 10.0.4.4: icmp_seq=2 ttl=63 time=8.40 ms\n64 bytes from 10.0.4.4: icmp_seq=3 ttl=63 time=2.11 ms\n64 bytes from 10.0.4.4: icmp_seq=4 ttl=63 time=4.61 ms\n\n--- 10.0.4.4 ping statistics ---\n4 packets transmitted, 4 received, 0% packet loss, time 3005ms\nrtt min/avg/max/mdev = 2.113/4.497/8.404/2.430 ms\n 1?: [LOCALHOST]                      pmtu 1500\n 1:  10.0.0.4                                              1.476ms \n 1:  10.0.0.4                                              1.036ms \n 2:  10.0.4.4                                              5.966ms reached\n     Resume: pmtu 1500 hops 2 back 2 \n\n[stderr]\n"
    }
  ]
}

Smazání a dealokace VMs

VM generují náklady a proto je po otestování konektivity odebereme, nebo dealokujeme. I při vypnutém VM, stav stopped, se za VM stále platí. Smazané VM je nutné znova vytvořit, zatímco dealokované, stav stopped (deallocated), je možné znova zapnout (pokud bude v datovém centru volná kapacita, případně ji máme rezervovanou). Síťová karta a disk u všech VM byly vytvořeny s nastavením deleteOption: 'Delete', takže se smažou spolu s VM a nemusíme je mazat samostatně. Příkazy spustíme vždy v příslušné subskripci, kde se VM nebo RG nachází.
az vm delete -g rg-spoke-app1-dev -n vm-conntest-app1-dev-swedencentral-001 --yes
az vm delete -g rg-spoke-app2-dev -n vm-conntest-app2-dev-swedencentral-001 --yes
az vm deallocate -g rg-hub-shared -n vm-router-shared-swedencentral-001
Případně je možné smazat vše, co jsme vytvořili a máme v resource group skupině.
az group delete -n rg-spoke-app1-dev --yes
az group delete -n rg-spoke-app2-dev --yes
az group delete -n rg-hub-shared --yes

Závěr

Nasadili jsme minimální hub-spoke topologii pomocí Bicep šablon přes Azure CLI. To je základ, na kterém lze stavět 🙌. Příště si přidáme privátní DNS, službu Azure Bastion, Azure Firewall místo Linux VM routeru, nastavíme na subnetech stavové L3/L4 firewally (NSG) a přidáme i point-to-site VPN Gateway.

Odkazy