CoursesAzure Administrator AssociateLoad balancing & Bastion

Load balancing & Bastion

Load Balancer, App Gateway/WAF, Bastion, DNS.

Intermediate30 min · lesson 11 of 15

Every big office used to run a mail room, and two very different people worked in it. One of them never opened anything. She read the outside of the envelope, building, floor, department number, and flung each letter into the right bin at astonishing speed. The other opened every letter, read what it actually asked for, sent invoices to accounting and complaints to legal, and shredded anything that smelled like a threat before it reached a desk. Azure hires both. Azure Load Balancer is the envelope reader. It works at *Layer 4* (the level of the network stack that knows only IP addresses, port numbers and the protocol, TCP or UDP), so it never looks inside. Application Gateway is the letter opener. It works at *Layer 7* (the application level, where URLs, headers and cookies live), and it can carry a WAF (web application firewall), the shredder for malicious requests. Half of this lesson is choosing the right one. The other half is building them with real commands.

Two questions pick the service for you

Every load-balancing question on the AZ-104 exam collapses into two questions of your own. First: what does the service need to see before it can route? If "push this TCP or UDP flow to a backend that is still alive" covers it, Layer 4 is plenty. If the decision depends on the request itself, sending /api/* to one pool, terminating TLS (transport layer security, the encryption behind HTTPS), blocking a SQL injection attempt, you need Layer 7. Second: where are your users? Regional services spread traffic inside one Azure region. Global services steer users between regions. Cross those two axes and you get four boxes. Load Balancer is regional Layer 4. Application Gateway is regional Layer 7 with a WAF. Azure Front Door is global Layer 7, with caching (a CDN, or content delivery network) and a WAF running in Microsoft's edge sites around the world. Traffic Manager is global too, but it works through DNS (domain name system, the internet's phone book). It answers the client's lookup with the name of the healthiest endpoint and then steps out of the traffic path completely. That is why it copes with any protocol at all, and also why its failover is only as fast as DNS caching allows, since every answer carries a TTL (time to live) that clients obey. Front Door sits *in* the traffic path using anycast routing, so it speaks HTTP and HTTPS only, but it fails over in seconds. Learn the grid by its two axes. Four unrelated product names will not stick.

Two questions pick the load-balancing service
What must it see to route? Where are the users?
Every AZ-104 load-balancing choice collapses onto these two axes
Regional + Layer 4 (IP, port, protocol only)
Azure Load Balancer
Five-tuple hash, not a proxy, so backends still see the client's real source IP
Regional + Layer 7 (URL, header, cookie)
Application Gateway + WAF_v2
Terminates TLS, routes by path or host, runs OWASP plus Microsoft rule sets
Global + Layer 7, sits in the traffic path
Azure Front Door
Anycast edge with caching and WAF. HTTP(S) only, but fails over in seconds
Global + any protocol, answers over DNS
Traffic Manager
Hands back a name, then leaves the traffic path. Failover bound by DNS TTL
Learn the 2x2 grid by its axes (Layer 4 vs Layer 7, regional vs global), not as four unrelated products.

Build a Standard Load Balancer

A load balancer is four objects bolted together. The frontend IP is the address clients connect to. The backend pool is a list of NICs (network interface cards, the virtual network adapters attached to your VMs or scale set). The health probe is how it decides who is alive. The rule ties a frontend port to a backend port. Inside, Azure Load Balancer is *not* a proxy. It runs a five-tuple hash over source IP, source port, destination IP, destination port and protocol, picks a backend from the result, rewrites the packet's destination and forwards it on. Your backend still sees the client's real source address. One date matters for the exam: the Basic SKU was retired on 30 September 2025 (SKU is Microsoft's word for a feature and pricing tier). Standard is the only realistic choice now, leaving aside the niche Gateway SKU used for chaining virtual appliances. Standard behaves differently in three ways worth remembering. It can spread across availability zones. It carries a 99.99% SLA (service level agreement, the uptime Microsoft commits to in writing). And it is *closed by default*: every inbound packet is dropped until an NSG (network security group, the packet filter you attach to a subnet or a NIC) explicitly permits it, exactly as you set up in the previous lesson.

build-standard-lb.sh
# 1. Public frontend IP (Standard SKU, zone-redundant)
az network public-ip create -g rg-web -n pip-lb-web \
--sku Standard --zone 1 2 3
# 2. The load balancer with a frontend and an empty backend pool
az network lb create -g rg-web -n lb-web --sku Standard \
--public-ip-address pip-lb-web \
--frontend-ip-name fe-web --backend-pool-name bp-web
# 3. Health probe: poll /healthz every 5 seconds
az network lb probe create -g rg-web --lb-name lb-web -n probe-http \
--protocol Http --port 80 --path /healthz --interval 5
# 4. Rule: frontend :80 -> backend :80, gated by the probe
az network lb rule create -g rg-web --lb-name lb-web -n rule-http \
--protocol Tcp --frontend-port 80 --backend-port 80 \
--frontend-ip-name fe-web --backend-pool-name bp-web \
--probe-name probe-http --idle-timeout 15
# 5. Put each VM's NIC into the pool
az network nic ip-config address-pool add -g rg-web \
--nic-name vm-web-1VMNic --ip-config-name ipconfig1 \
--lb-name lb-web --address-pool bp-web
# Output of step 2 (trimmed):
# {
# "loadBalancer": {
# "name": "lb-web",
# "provisioningState": "Succeeded",
# "sku": { "name": "Standard" }
# }
# }

Grab the frontend address and hit it a few times. Traffic is spread by hash, not by strict round-robin. Each new TCP connection leaves from a fresh source port, so the hash changes and the backend usually changes with it. Do not expect a tidy A, B, A, B pattern:

verify-distribution
$ az network public-ip show -g rg-web -n pip-lb-web \
--query ipAddress -o tsv
20.242.150.87
$ for i in 1 2 3 4; do curl -s http://20.242.150.87; done
Hello from vm-web-1
Hello from vm-web-2
Hello from vm-web-2
Hello from vm-web-1

When a probe fails several times in a row, that instance drops out of rotation within seconds, and connections already in flight are allowed to finish rather than being cut off mid-sentence. Point the probe at /healthz, an endpoint that actually checks the app's real dependencies, rather than at /. A bare / tells you the web server answered the door. It says nothing about whether the application behind it can still reach its database, and you will cheerfully keep feeding customers to a dead app.

SNAT port exhaustion: the outage that gets blamed on the app
When your backend VMs make *outbound* calls through a public Standard Load Balancer, each instance receives a small fixed ration of SNAT ports (source network address translation, the port-swapping trick that lets many private machines share one public IP). The ration is 1,024 ports for pools of up to 50 VMs, and it shrinks as the pool grows. A chatty app hammering one external API burns through them, and outbound connections begin timing out. The failures come and go, and only under load, which is why this classic outage gets misdiagnosed as an application bug for days at a time. It got stricter, too: since 30 September 2025 new deployments get *no* default outbound internet access at all. Plan your egress on purpose. Attach a NAT Gateway (network address translation gateway) to the subnet, which holds over 64,000 ports per public IP and hands them out dynamically, instead of leaning on the load balancer's implicit SNAT.

Layer 7: Application Gateway and the WAF

Application Gateway *is* a proxy. It answers the client's TCP connection itself, unwraps the TLS, reads the whole HTTP request, then opens a brand-new connection to a backend. That extra hop is what buys you path-based routing (/api/* and /images/* going to different backend pools), routing by hostname, cookie-based session affinity and TLS offload. The WAF_v2 SKU adds the web application firewall, driven by managed rule sets. Deploy Microsoft_DefaultRuleSet 2.1, which stacks Microsoft's threat intelligence on top of the OWASP Core Rule Set (OWASP is the Open Worldwide Application Security Project, a nonprofit whose published rules catch the classic web attacks) to stop SQL injection, cross-site scripting and known CVE exploits (a CVE, or common vulnerabilities and exposures entry, is a publicly catalogued software flaw with an ID number). A WAF policy runs in one of two modes. Detection logs what it would have blocked and blocks nothing, which is where you start, so you can watch for false positives on genuine customer traffic. Prevention actually enforces. Want the same shield in every region at once? Front Door Premium runs a WAF out at the edge instead. Two practical facts round this out. The gateway insists on a *dedicated subnet* of its own, and v2 can autoscale, though the example below pins two fixed instances. At a baseline of roughly $300 a month before you serve a single request, it is the priciest regional component here, so small internal apps often go without.

appgw-waf.sh
# WAF policy with the modern managed rule set, then enforce it
az network application-gateway waf-policy create -g rg-web \
-n wafpol-web --type Microsoft_DefaultRuleSet --version 2.1
az network application-gateway waf-policy policy-setting update \
-g rg-web --policy-name wafpol-web \
--mode Prevention --state Enabled
# App Gateway WAF_v2 in its own subnet, policy attached
az network application-gateway create -g rg-web -n agw-web \
--sku WAF_v2 --capacity 2 --priority 100 \
--vnet-name vnet-prod --subnet snet-agw \
--public-ip-address pip-agw --waf-policy wafpol-web \
--servers 10.0.1.4 10.0.1.5
# Deployment runs ~6-8 minutes, then:
# "provisioningState": "Succeeded",
# "operationalState": "Running"

Bastion: reach VMs that have no public address

Not one VM in this design has a *public IP*. So how do you get a shell on one? The old answer was a jump box: a hardened VM with a public address that you log into first and hop inward from. But a jump box is one more machine to patch, and the minute it exists, its open port 22 (SSH, or secure shell, the standard remote login for Linux) or port 3389 (RDP, or remote desktop protocol, the Windows equivalent) starts getting scanned by strangers. Azure Bastion is Microsoft's managed version of that jump host. You reach Bastion over TLS on port 443, from the portal or the CLI (command line interface), and Bastion opens the RDP or SSH session to the VM's private address from inside the VNet (virtual network). No public IPs on your VMs, no inbound management ports in your NSGs, nothing for a scanner to find. Two hard requirements catch people out, on the exam and in production: the subnet must be named exactly AzureBastionSubnet, and it must be at least a /26.

bastion.sh
# Bastion demands a dedicated subnet with this EXACT name, >= /26
az network vnet subnet create -g rg-web --vnet-name vnet-prod \
-n AzureBastionSubnet --address-prefixes 10.0.255.0/26
az network public-ip create -g rg-web -n pip-bastion --sku Standard
# Standard SKU + tunneling = native ssh/rdp from your terminal
# (deployment takes ~10 minutes)
az network bastion create -g rg-web -n bas-prod \
--vnet-name vnet-prod --public-ip-address pip-bastion \
--sku Standard --enable-tunneling true
# Connect with your own SSH key -- no public IP, no open port 22
az network bastion ssh -g rg-web -n bas-prod \
--target-resource-id $(az vm show -g rg-web -n vm-web-1 \
--query id -o tsv) \
--auth-type ssh-key --username azureuser \
--ssh-key ~/.ssh/id_ed25519
# Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-1030-azure x86_64)
# azureuser@vm-web-1:~$

Learn the SKU ladder. Developer is free, limited to dev and test, allows one connection at a time and needs no dedicated subnet. Basic gives you browser-based sessions. Standard adds native-client tunneling, file transfer, and scaling up to 50 instances. Premium adds session recording and a private-only deployment. Bastion bills by the hour whether anyone is connected or not, around $140 a month even at Basic, so tear it down when a lab session ends or stay on the Developer SKU. Production teams pay the bill without blinking. It is what deleting every public management port in the estate costs.

DNS, and where this design goes next

Azure DNS hosts your public zones on Microsoft's nameservers, and you manage them with the same az commands and the same RBAC (role-based access control, the permission system) as everything else (az network dns record-set a add-record ...). The detail worth carrying into the exam is the alias record. The DNS standard forbids a CNAME at the apex of a zone, meaning the bare contoso.com with nothing in front of it. An alias record is Azure's way around that. It points straight at an Azure public IP, a Traffic Manager profile or a Front Door endpoint, and it *follows the resource*. If your load balancer's address ever changes, the record updates itself. Its private sibling, the private DNS zone, resolves names inside a VNet with no exposure to the internet whatsoever.

Notice which way traffic has been flowing all lesson. Inward, from the internet, filtered by a WAF, spread by a hash, administered over TLS, and never landing on a VM with a public address. The next lesson turns the arrow around. Your VMs also call *outward* to Azure PaaS services (platform as a service: the storage accounts, databases and key vaults that Microsoft runs on your behalf), and by default those calls travel to public endpoints over the internet. Private Endpoints pull those services into your VNet as ordinary private IP addresses, and the private DNS zones you met a paragraph ago are precisely what makes their names resolve to those addresses. That is the last piece of a network in which nothing important is public.

Pick the balancer by how deep it has to look. If all you need is port 443 delivered to a pool of NICs with a health check in front, Standard Load Balancer does the job and costs little. If you need host headers, path routing, TLS termination or OWASP rules, that is Application Gateway, or Front Door when the audience is worldwide. Confusing the two is one of the most reliable traps on the exam.

Bastion is the operational half of the same idea: a managed jump host living inside your VNet, so the network security groups on your VMs can deny SSH and RDP from the internet outright. When you still need a temporary management opening, pair it with Just-In-Time VM access in Microsoft Defender for Cloud, which opens a port for one named person for a fixed window and then closes it again. Azure DNS, public zones and private ones, keeps your names steady while the frontends behind them come and go.

Try this

Take this to a lab. Create a Standard public Load Balancer, or point at an App Gateway you already run. At the very least, list the SKUs and frontend IPs so you can see the Layer 4 and Layer 7 products sitting side by side. Only create Bastion in a live lab if you are happy to pay for every hour it exists.

terminal
RG=rg-lab-lb
az group create -n $RG -l eastus
az network public-ip create -g $RG -n pip-lb --sku Standard --allocation-method Static
az network lb create -g $RG -n lb-lab --sku Standard --public-ip-address pip-lb --frontend-ip-name fe --backend-pool-name be
az network lb show -g $RG -n lb-lab --query "{sku:sku.name,fe:frontendIpConfigurations[0].name}" -o json
az network lb list -g $RG -o table
output
$ az network lb show -g rg-lab-lb -n lb-lab --query "{sku:sku.name,fe:frontendIpConfigurations[0].name}" -o json
{
"sku": "Standard",
"fe": "fe"
}
# Sample output — Azure Load Balancer = L4; Application Gateway = L7 HTTP + optional WAF.

Takeaway

Three lines to carry into the exam room. Load Balancer moves TCP and UDP flows at Layer 4. Application Gateway reads HTTP at Layer 7 and can run a WAF. Bastion gives you RDP and SSH sessions without a single public management port on any VM.

Your next move: put Bastion in a dedicated AzureBastionSubnet of /26 or larger, prove you can reach a VM through it, then strip the public IPs off the old jump boxes.

Quick check
01Backend VMs behind a public Standard Load Balancer start dropping outbound API calls, but only under heavy load and only some of the time. Nobody touched the app. What actually fixes it?
Correct — This is SNAT port exhaustion. A NAT Gateway hands out more than 64,000 ports per public IP, allocated on demand, instead of the tiny fixed ration the load balancer gives each instance.
Incorrect — The per-instance SNAT ration gets smaller as the pool grows, so extra VMs bring the exhaustion on sooner.
Incorrect — Probes decide which instances receive inbound traffic. They have no bearing on the outbound ports that are running out.
Incorrect — That is the exact misdiagnosis this lesson warns about. The ports run out in the platform, so a restart only buys time until the next wave of timeouts.
02You are deploying Azure Bastion so administrators can reach virtual machines that have no public IP address. Bastion needs a dedicated subnet in the virtual network. What must that subnet look like?
Incorrect — GatewaySubnet is the reserved name for VPN and ExpressRoute gateways, a different service entirely.
Incorrect — The name is fixed, not free-form, and the minimum size is /26, not /24.
Correct — Both requirements are hard ones. The name has to be exactly AzureBastionSubnet, and the subnet has to be a /26 or larger.
Incorrect — AzureFirewallSubnet is the reserved subnet name for Azure Firewall, which is a different service.
03A web application runs in a single Azure region. It has to route by URL path, sending /api/* to one backend pool and /images/* to another, and it also has to block SQL injection and cross-site scripting attempts. Which service is the BEST choice?
Incorrect — Azure Load Balancer works at Layer 4, where it sees IP, port and protocol only, so it cannot read a URL path or filter a malicious request.
Correct — Application Gateway is the regional Layer 7 proxy that routes by path, and its web application firewall blocks injection and cross-site scripting attempts.
Incorrect — Traffic Manager answers a DNS lookup and then leaves the traffic path, so it never sees a URL or a request to inspect.
Incorrect — Front Door is the global Layer 7 and WAF service at the edge. For a workload that lives in one region, the grid points at the regional Application Gateway instead.

Related