AZ-104 Refresher Chapter 3 · Virtual networks

Chapter 3

Virtual networks: subnets, peering, IPs, routing and DNS

📖 Theory 35 min🛠 Lab 25 minVirtual networking · 15–20%

The network is the foundation that VMs, private endpoints and App Service integration plug into. In this chapter you build a small hub-and-spoke network that the rest of the guide uses.

Part A

Theory

Virtual networks and subnets

A virtual network (VNet) is your private network in Azure. It lives in one region and one subscription, and has one or more address spaces in CIDR notation, like 10.20.0.0/16. You split it into subnets, and resources like VM network interfaces get an IP address from a subnet.

Planning the address space is the part people get wrong in real life and in the exam:

Five addresses are reserved in every subnet

Azure reserves five IP addresses in each subnet, so a /24 has 251 usable addresses, not 254. The smallest subnet for IPv4 is a /29 (8 addresses, 3 usable).

snet-web · 10.20.1.0/24 .0network .1gateway .2Azure DNS .3Azure DNS .4 … .254251 usable — the first VM gets .4 .255broadcast Quick formula: usable = 2^(32 − prefix) − 5. /24 → 251 · /26 → 59 · /27 → 27 · /28 → 11 · /29 → 3
Reserved addresses: the first four and the last one of each subnet.

Special subnets

Some Azure services need a subnet with an exact name and a minimum size. Expect at least one question on this:

Subnet nameForMinimum size
GatewaySubnetVPN gateway and ExpressRoute gateway/29 (use /27)
AzureBastionSubnetAzure Bastion Basic/Standard/Premium/26
AzureFirewallSubnetAzure Firewall/26
RouteServerSubnetAzure Route Server/26 (use /27)

Other subnets can be delegated to a service, which then injects its own resources there. Examples: Microsoft.Web/serverFarms for App Service VNet integration (chapter 8) or Microsoft.ContainerInstance/containerGroups for ACI in a VNet. A delegated subnet can only be used by that service.

Private subnets and outbound internet access

Until recently, any VM without a public IP still got default outbound access to the internet through a hidden Microsoft IP. That's being retired: new VNets now create private subnets by default. In a private subnet a VM can only reach the internet through an explicit outbound method. In order of precedence:

  1. NAT Gateway on the subnet (recommended for production).
  2. A public IP on the VM's NIC.
  3. A Standard Load Balancer with outbound rules (chapter 6).

In the lab you'll turn private-subnet mode off for snet-web so your VMs can install a web server in chapter 5. In chapter 6 you then add a proper outbound rule.

IP addresses

Private IP addresses

Every NIC gets a private IP from its subnet, either dynamic (the next free address; it's kept as long as the NIC exists, even across reboots) or static (you pick an address from the subnet). Always set static IPs in Azure, never inside the guest OS. If you hardcode an IP in Windows or Linux and it doesn't match, the VM loses connectivity.

Public IP addresses

A public IP address is a separate resource that you associate with a VM NIC, a public load balancer, an Application Gateway, a VPN gateway, a NAT Gateway, Azure Bastion or Azure Firewall. The choices when you create one:

A public IP prefix reserves a contiguous block of public IPs (like a /28), which is handy when partners need to allow-list your addresses.

Exam trap

"You add a Standard public IP to a VM but can't reach it on port 80." Standard SKU IPs are closed by default. You need an NSG rule that allows port 80 on the NIC or subnet.

Virtual network peering

Peering connects two VNets so their resources talk to each other with private IPs over the Microsoft backbone, with low latency and no gateway in between. Regional peering connects VNets in the same region, global peering connects VNets in different regions. Peering also works across subscriptions and tenants.

The rules you must know:

Hub VNet10.10.0.0/16 VPN / ERgateway Firewall/ NVA Spoke A10.20.0.0/16 Spoke B10.30.0.0/16 peeringpeering ✕ no direct path (not transitive) Fix: UDRs to the firewall/NVA in the hub, or peer A ↔ B directly, or use Virtual WAN
Hub and spoke. The hub holds shared services; spokes hold workloads. Spoke-to-spoke traffic needs routing through the hub.

Peering settings

Each side of a peering has four settings. The portal words them as "allow" questions:

Exam trap

"Spokes must reach on-premises through the hub's VPN gateway." On the hub peering: Allow gateway transit. On each spoke peering: Use remote gateways. Not "allow forwarded traffic", which is about NVAs.

Routing

Azure routes traffic between subnets, peered VNets, on-premises and the internet automatically using system routes. Every subnet starts with these:

Address prefixNext hop
The VNet's own address spaceVirtual network
0.0.0.0/0Internet
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10None (dropped), unless they're in your VNet

Azure adds more system routes when you add peering (next hop VNet peering), a VPN/ExpressRoute gateway (routes learned via BGP) or service endpoints.

User-defined routes (UDRs)

To override the defaults, you create a route table with routes and associate it with subnets. The classic use is sending all traffic through a firewall (forced tunnelling): a route 0.0.0.0/0 → Virtual appliance 10.10.2.4.

The next hop types for a UDR are:

Rules for route tables:

How Azure picks a route

When several routes match a destination, Azure decides in two steps:

  1. Longest prefix match wins: a route for 10.20.1.0/24 beats 10.20.0.0/16, which beats 0.0.0.0/0.
  2. If the prefixes are equally long: user-defined route > BGP route > system route.

To see what actually applies, open a VM's NIC → Effective routes, or use Network Watcher → Next hop (chapter 9). Both show the combined result of system routes, BGP and UDRs.

Exam trap

"After adding a route 0.0.0.0/0 → Virtual appliance, VMs can't reach anything." Check that IP forwarding is enabled on the NVA's NIC and that the NVA is running. UDRs don't check whether the next hop works.

Name resolution and Azure DNS

By default VMs use Azure-provided DNS at the virtual IP 168.63.129.16. It resolves public names and the VM names within the same VNet, but not across VNets. For anything more, there are three options:

Public DNS zones

An Azure DNS zone hosts the records of a public domain like contoso.com. Azure DNS doesn't sell domains. You buy the domain at a registrar and delegate it by setting the four Azure NS name servers at the registrar. For a subdomain (like dev.contoso.com), you create a child zone and add an NS record in the parent zone.

Record types you should recognise: A and AAAA (IPv4/IPv6 address), CNAME (alias to another name, not allowed at the zone apex), MX (mail), TXT (verification, SPF), SRV, CAA and NS/SOA. An alias record set points to an Azure resource (a public IP, Traffic Manager profile or Front Door) and updates automatically when its IP changes. Alias records can be used at the apex (contoso.com itself), which a CNAME can't.

Private DNS zones

A private DNS zone (like az104.lab or privatelink.file.core.windows.net) is resolvable only from VNets that have a virtual network link to it. A link can have auto-registration turned on:

az104.labprivate DNS zone vm-web1 A 10.20.1.4 · vm-web2 A 10.20.1.5 vnet-hubresolution only vnet-spokeauto-registration on link: can querylink: query + register
VMs in the spoke register themselves in az104.lab; VMs in the hub can resolve those names.

Troubleshooting connectivity

When two things can't talk, work through the layers in this order. The tools are covered in depth in chapter 9:

  1. Is the target running and listening? (service started, OS firewall)
  2. Is there a route? NIC → Effective routes, or Network Watcher Next hop. Look for UDRs to dead NVAs, missing peering, or "None".
  3. Does an NSG block it? NIC → Effective security rules, or Network Watcher IP flow verify (chapter 6).
  4. Does the name resolve correctly? nslookup from the VM: does it return the private or the public IP?
  5. End-to-end test: Network Watcher Connection troubleshoot checks all of the above in one go.
AZ-305 link

AZ-305 asks you to choose between hub-and-spoke with peering and Azure Virtual WAN (managed hub, transitive routing built in, better for many branches), and to design IP address plans that leave room for growth and never overlap with on-premises. "Plan the address space first" is always part of the right answer.

Self-check

1. How many VMs can you place in a subnet with prefix /27?

C. 32 addresses − 5 reserved = 27.

2. VNet A is peered with B, and B is peered with C. A VM in A can't reach a VM in C. What's the simplest fix?

B. Peering isn't transitive. Gateway transit is for VPN/ExpressRoute gateways, not for VM-to-VM traffic.

3. A subnet has system route 0.0.0.0/0 → Internet and a UDR 0.0.0.0/0 → Virtual appliance 10.10.2.4. Traffic to 10.20.5.8 goes where, if 10.20.0.0/16 is the VNet?

D. Longest prefix match comes first. UDR beats system only when prefixes are equally long.

4. You want contoso.com (the apex) to point at the public IP of a load balancer, and stay correct if the IP changes. What do you create?

A. CNAMEs aren't allowed at the apex; alias records are and follow the resource.

5. You need to deploy Azure Bastion Standard. Which subnet do you need?

C. The name is exact and the minimum is /26.

Part B

Lab: build the hub-and-spoke network

You build the network that every later chapter uses. Paste the variables first:

RG=rg-az104-lab; LOC=westeurope; LOC2=northeurope; INIT=xx
VNetAddress spaceSubnets
vnet-hub10.10.0.0/16snet-shared 10.10.1.0/24
vnet-spoke10.20.0.0/16snet-web 10.20.1.0/24 · snet-data 10.20.2.0/24
(snet-app 10.20.3.0/24 is added with Bicep in chapter 4)
  1. Task

    Create the hub VNet

    Create vnet-hub with the address space and subnet from the table above, in your lab region, in rg-az104-lab. Don't add Bastion, Firewall or DDoS protection.

    Done when
    • vnet-hub exists with one subnet snet-shared.
    • Its tags show env and course. Who added them?
    Solution · Portal
    1. Create a resource → Virtual network. Resource group rg-az104-lab, name vnet-hub, your region.
    2. Security tab: leave everything off.
    3. IP addresses tab: change the address space to 10.10.0.0/16, edit the default subnet to name snet-shared, range 10.10.1.0/24.
    4. Review + create. The tags come from your chapter 2 Modify policy.
    Solution · Azure CLI
    az network vnet create -g $RG -n vnet-hub -l $LOC \
      --address-prefixes 10.10.0.0/16 --subnet-name snet-shared --subnet-prefixes 10.10.1.0/24
    az network vnet show -g $RG -n vnet-hub --query tags
  2. Task

    Create the spoke VNet

    Create vnet-spoke with snet-web and snet-data. One requirement: VMs in snet-web must be able to reach the internet without a public IP or NAT gateway for now (they download a web server in chapter 5). snet-data stays a private subnet.

    Done when
    • Both subnets exist with the right ranges.
    • snet-web has default outbound access enabled, snet-data doesn't.
    • You can say how many IPs are usable in snet-data.
    Hint

    When you edit a subnet, look for the checkbox Enable private subnet (no default outbound access).

    Solution · Portal
    1. Create a resource → Virtual network: name vnet-spoke, address space 10.20.0.0/16.
    2. Edit the default subnet → snet-web, 10.20.1.0/24, untick Enable private subnet.
    3. Add a subnet → snet-data, 10.20.2.0/24, keep Enable private subnet ticked.
    4. Review + create. Usable IPs in a /24: 251.
    Solution · Azure CLI
    az network vnet create -g $RG -n vnet-spoke -l $LOC --address-prefixes 10.20.0.0/16
    az network vnet subnet create -g $RG --vnet-name vnet-spoke -n snet-web \
      --address-prefixes 10.20.1.0/24 --default-outbound-access true
    az network vnet subnet create -g $RG --vnet-name vnet-spoke -n snet-data \
      --address-prefixes 10.20.2.0/24 --default-outbound-access false
    az network vnet subnet list -g $RG --vnet-name vnet-spoke \
      --query "[].{name:name, prefix:addressPrefix, defaultOutbound:defaultOutboundAccess}" -o table
  3. Task

    Peer the hub and the spoke

    Connect vnet-hub and vnet-spoke so resources in both can reach each other with private IPs. There's no gateway or firewall, so leave gateway transit off. Name the links peer-hub-to-spoke and peer-spoke-to-hub.

    Done when
    • Both VNets show the peering with status Connected.
    • You know what the status would be if you'd created only one side.
    Solution · Portal
    1. Open vnet-hub → Settings → Peerings → Add.
    2. Remote virtual network summary: peering link name peer-spoke-to-hub, virtual network vnet-spoke, keep Allow vnet-spoke to access vnet-hub ticked.
    3. Local virtual network summary: peering link name peer-hub-to-spoke, keep access allowed. Add.
    4. With one side only, the status would be Initiated.
    Solution · Azure CLI
    az network vnet peering create -g $RG -n peer-hub-to-spoke --vnet-name vnet-hub \
      --remote-vnet vnet-spoke --allow-vnet-access
    az network vnet peering create -g $RG -n peer-spoke-to-hub --vnet-name vnet-spoke \
      --remote-vnet vnet-hub --allow-vnet-access
    az network vnet peering list -g $RG --vnet-name vnet-hub --query "[].{name:name, state:peeringState}" -o table
  4. Task

    Give your VMs DNS names

    Create a private DNS zone az104.lab. VMs in the spoke must register themselves automatically; VMs in the hub must be able to resolve those names but not register their own.

    Done when
    • The zone has two virtual network links, with auto-registration only on the spoke link.
    • (You'll see the VM records appear in chapter 5.)
    Solution · Portal
    1. Create a resource → Private DNS zone: name az104.lab, resource group rg-az104-lab.
    2. Open the zone → DNS Management → Virtual Network Links → Add: name link-spoke, VNet vnet-spoke, tick Enable auto registration.
    3. Add another: link-hub, VNet vnet-hub, auto registration off.
    Solution · Azure CLI
    az network private-dns zone create -g $RG -n az104.lab
    az network private-dns link vnet create -g $RG -z az104.lab -n link-spoke -v vnet-spoke -e true
    az network private-dns link vnet create -g $RG -z az104.lab -n link-hub   -v vnet-hub   -e false
  5. Task

    Add a user-defined route

    Create a route table rt-spoke and attach it to snet-web. Add one route named blackhole-testnet that drops all traffic to the documentation range 203.0.113.0/24. You'll see this route again in chapter 9 with Network Watcher.

    Done when
    • rt-spoke is associated with snet-web and has the route with next hop type None.
    Solution · Portal
    1. Create a resource → Route table: name rt-spoke, your region, Propagate gateway routes = Yes.
    2. Open it → Routes → Add: name blackhole-testnet, destination type IP Addresses, prefix 203.0.113.0/24, next hop None.
    3. Subnets → Associate: vnet-spoke / snet-web.
    Solution · Azure CLI
    az network route-table create -g $RG -n rt-spoke -l $LOC
    az network route-table route create -g $RG --route-table-name rt-spoke -n blackhole-testnet \
      --address-prefix 203.0.113.0/24 --next-hop-type None
    az network vnet subnet update -g $RG --vnet-name vnet-spoke -n snet-web --route-table rt-spoke
  6. Task

    Reserve a public IP for the load balancer

    Create a public IP pip-lbe-web for the load balancer of chapter 6. It must survive the failure of one availability zone and keep the same address forever.

    Done when
    • The IP shows SKU Standard, assignment Static and zones 1, 2, 3. Write the address down.
    Solution · Portal

    Create a resource → Public IP address: name pip-lbe-web, IPv4, SKU Standard, tier Regional, availability zone Zone-redundant, routing preference Microsoft network. Standard is always static.

    Solution · Azure CLI
    az network public-ip create -g $RG -n pip-lbe-web -l $LOC --sku Standard \
      --allocation-method Static --zone 1 2 3 --query "publicIp.ipAddress" -o tsv
    Cost

    A Standard public IP costs a few euros per month. VNets, peering (without traffic), route tables and private DNS zones cost almost nothing.

  7. Task · optional, needs your own domain

    Host a subdomain in Azure DNS

    Make Azure DNS authoritative for the subdomain lab.yourdomain.com, while your registrar keeps hosting the main domain. Then create the name web.lab.yourdomain.com pointing at pip-lbe-web in a way that keeps working if the IP ever changes. (It serves a website after chapter 6.)

    Don't touch the main domain

    Only add records for lab at your registrar. Never change the name servers of the domain itself, or your existing email and websites stop working.

    Done when
    • A public lookup of the NS records of lab.yourdomain.com returns four Azure name servers (ns1-xx.azure-dns.com etc.).
    • web.lab.yourdomain.com resolves to the address of pip-lbe-web.
    • You can explain why you used an alias record instead of a normal A record.
    Hint

    Delegating a subdomain = NS records with the name lab in the parent zone (at your registrar), pointing at the name servers Azure gives your new zone. Delegation can take from a few minutes up to the parent's NS TTL to be visible.

    Solution · Portal
    1. Create a resource → DNS zone: resource group rg-az104-lab, name lab.yourdomain.com. (Leave "This zone is a child of an existing zone hosted in Azure DNS" unticked: the parent is at your registrar.)
    2. Open the zone → Overview: copy the four Name servers.
    3. At your registrar's DNS management for yourdomain.com: add four NS records with host/name lab, each with one Azure name server as value (keep the trailing dot if the registrar wants it).
    4. Back in the zone: + Record set → name web, type A, Alias record set: Yes, alias type Azure resource → pip-lbe-web.
    5. Test from your Linux VM: nslookup -type=NS lab.yourdomain.com and nslookup web.lab.yourdomain.com.

    An alias record follows the Azure resource: if the IP changes or the resource is deleted, DNS updates (or empties) automatically, so you never get a dangling record pointing at an IP someone else might get.

    Solution · Azure CLI
    ZONE=lab.yourdomain.com
    az network dns zone create -g $RG -n $ZONE
    az network dns zone show -g $RG -n $ZONE --query nameServers -o tsv
    # → add these four as NS records named "lab" at your registrar
    
    PIPID=$(az network public-ip show -g $RG -n pip-lbe-web --query id -o tsv)
    az network dns record-set a create -g $RG -z $ZONE -n web --target-resource $PIPID
    
    nslookup -type=NS $ZONE            # after the delegation is live
    nslookup web.$ZONE
    Cost

    A public DNS zone costs about €0.50 per month plus a tiny amount per million queries.

  8. Task

    Protect the hub from deletion

    Make sure nobody can delete vnet-hub by accident, while still allowing changes to it. Then try to delete it to prove it works.

    Done when
    • Deleting vnet-hub fails with a lock error, and the VNet still exists.
    Solution · Portal

    vnet-hub → Settings → Locks → Add: name lock-hub-nodelete, type Delete (CanNotDelete). Then Overview → Delete → it fails.

    Solution · Azure CLI
    az lock create -n lock-hub-nodelete -g $RG --resource-name vnet-hub \
      --resource-type Microsoft.Network/virtualNetworks --lock-type CanNotDelete
    az network vnet delete -g $RG -n vnet-hub     # fails: ScopeLocked

    Remember this lock: chapter 10's cleanup has to remove it first.

Checkpoint
  • vnet-hub (locked) and vnet-spoke, peered.
  • snet-web (default outbound on, route table rt-spoke) and snet-data (private).
  • Private DNS zone az104.lab linked to both VNets.
  • Public IP pip-lbe-web, unused until chapter 6.
  • Optional: public DNS zone lab.yourdomain.com, delegated from your registrar, with alias record web → pip-lbe-web.