Application Gateway & WAF
Why this matters
Application Gateway is Azure's L7 (HTTP) load balancer — the thing you reach for when you need path-based routing, host-based routing, TLS termination, or a Web Application Firewall, none of which the L4 Load Balancer from module 04 can do. It's also one of the two resources in this track that bill hourly even when idle (Azure Firewall is the other), so this module is where cost discipline stops being optional. You'll build a working gateway, route by URL path, and turn on the WAF.
Concepts
L7 load balancing vs. the L4 Load Balancer
Application Gateway is the L7 reverse proxy / load balancer from track 1: it terminates the HTTP(S) connection, reads the request (host header, URL path, cookies), and makes routing decisions based on Layer-7 content — things the Azure Load Balancer (L4, module 04) fundamentally can't see. Rule of thumb: if the decision depends on the URL, host header, or requires TLS termination or a WAF, you need Application Gateway; if it's raw TCP/UDP flow distribution, the L4 Load Balancer is cheaper and simpler.
The Application Gateway components
App Gateway wires together a chain of pieces, and the terminology is worth memorizing because errors reference them: a frontend IP (public and/or private), one or more listeners (a frontend IP + port + protocol, optionally a hostname and TLS cert), backend pools (the servers/IPs/FQDNs receiving traffic), HTTP settings (backend port, protocol, probe, timeouts), a health probe, and routing rules that tie a listener to a backend pool via HTTP settings. Path-based rules add a URL path map that sends different paths to different backend pools.
Its own subnet, and the SKU/tier choice
App Gateway must live in its own dedicated subnet (nothing else in it),
which is why module 01 had you pre-create appgw-subnet. It comes in
Standard_v2 (load balancing only) and WAF_v2 (adds the Web Application
Firewall) tiers, both on the v2 autoscaling engine. v2 bills a fixed hourly
gateway charge plus a capacity-unit charge — meaning even an idle WAF_v2
gateway accrues cost every hour it exists. Pick WAF_v2 when you want the
firewall; otherwise Standard_v2.
TLS termination
App Gateway can terminate TLS: clients connect over HTTPS to a listener that holds the certificate, the gateway decrypts, inspects (needed for path routing and WAF), and then forwards to the backend over HTTP or a re-encrypted HTTPS (end-to-end TLS). Terminating at the gateway centralizes certificate management and is what lets the WAF and path-based routing see request content. This is the "TLS termination at the edge" pattern from track 1's HTTP/TLS material.
The Web Application Firewall (WAF)
The WAF (on the WAF_v2 tier) inspects HTTP requests against managed rule sets (OWASP Core Rule Set) to block common attacks — SQL injection, XSS, path traversal, and so on. It runs in two modes: Detection (logs matches, blocks nothing) and Prevention (actively blocks). This is the "web application firewall / OWASP filtering" concept from track 1, operating at L7 — distinct from an NSG, which filters at L3/L4 on IP and port and has no idea what HTTP is. Start in Detection mode to find false positives before switching to Prevention.
Command reference
| Command | What it does | Example |
|---|---|---|
az network application-gateway create |
Creates an App Gateway (frontend, listener, pool, rule) | az network application-gateway create -g agw-lab-rg -n web-agw --sku WAF_v2 --capacity 2 --vnet-name lab-vnet --subnet appgw-subnet --public-ip-address agw-pip --frontend-port 80 --http-settings-port 80 --http-settings-protocol Http --priority 100 |
az network application-gateway address-pool create |
Adds a backend pool | az network application-gateway address-pool create -g agw-lab-rg --gateway-name web-agw -n api-pool --servers 10.0.2.10 10.0.2.11 |
az network application-gateway url-path-map create |
Creates a path-based routing map | az network application-gateway url-path-map create -g agw-lab-rg --gateway-name web-agw -n pathmap --paths /api/* --address-pool api-pool --default-address-pool appGatewayBackendPool --http-settings appGatewayBackendHttpSettings --default-http-settings appGatewayBackendHttpSettings |
az network application-gateway probe create |
Adds a custom health probe | az network application-gateway probe create -g agw-lab-rg --gateway-name web-agw -n api-probe --protocol Http --path /health --host 127.0.0.1 |
az network application-gateway waf-config set |
Configures the WAF mode/ruleset | az network application-gateway waf-config set -g agw-lab-rg --gateway-name web-agw --enabled true --firewall-mode Prevention --rule-set-type OWASP --rule-set-version 3.2 |
az network application-gateway show |
Shows gateway config | az network application-gateway show -g agw-lab-rg -n web-agw |
az network application-gateway show-backend-health |
Shows backend health status | az network application-gateway show-backend-health -g agw-lab-rg -n web-agw |
Flag breakdown — az network application-gateway create ... --sku WAF_v2 --capacity 2 --vnet-name lab-vnet --subnet appgw-subnet --public-ip-address agw-pip --frontend-port 80 --http-settings-port 80 --http-settings-protocol Http --priority 100:
--sku:Standard_v2orWAF_v2(WAF_v2 adds the firewall; both bill hourly + capacity units).--capacity: number of instances / capacity units (min for v2 autoscale).--vnet-name/--subnet: the dedicated subnet the gateway lives in.--public-ip-address: the frontend public IP (must be Standard SKU for v2).--frontend-port: the port the listener accepts on (e.g. 80/443).--http-settings-port/--http-settings-protocol: how the gateway talks to the backend.--priority: routing-rule priority (required for v2; unique per gateway).
Flag breakdown — az network application-gateway waf-config set ... --enabled true --firewall-mode Prevention --rule-set-type OWASP --rule-set-version 3.2:
--enabled: turns the WAF on/off.--firewall-mode:Detection(log only) orPrevention(block).--rule-set-type/--rule-set-version: managed rule set (OWASP) and its version.
Hands-on exercises
Cost warning: App Gateway v2 bills hourly + capacity units from the moment it's created. Do these exercises in one sitting and delete the group immediately after. Provisioning a gateway takes several minutes.
Set up the group, VNet, gateway subnet, and a frontend public IP:
az group create --name agw-lab-rg --location eastus
az network vnet create -g agw-lab-rg -n lab-vnet --address-prefixes 10.0.0.0/16 \
--subnet-name appgw-subnet --subnet-prefixes 10.0.1.0/24
az network vnet subnet create -g agw-lab-rg --vnet-name lab-vnet \
-n backend-subnet --address-prefixes 10.0.2.0/24
az network public-ip create -g agw-lab-rg -n agw-pip \
--sku Standard --allocation-method Static
Create the Application Gateway (WAF_v2).
az network application-gateway create -g agw-lab-rg -n web-agw \ --sku WAF_v2 --capacity 2 --vnet-name lab-vnet --subnet appgw-subnet \ --public-ip-address agw-pip --frontend-port 80 \ --http-settings-port 80 --http-settings-protocol Http --priority 100This takes several minutes. > Verify:
az network application-gateway show -g agw-lab-rg -n web-agw --query operationalStatereturnsRunning.Check the default backend health. With no real backends yet, the default pool is empty:
az network application-gateway show-backend-health -g agw-lab-rg -n web-agwVerify: you see the default backend pool and HTTP settings; health is empty/unknown because there are no servers.
Add a backend pool. Point it at two IPs in
backend-subnet(in a full lab these would be web servers oraz container createinstances serving HTTP):az network application-gateway address-pool create -g agw-lab-rg \ --gateway-name web-agw -n api-pool --servers 10.0.2.10 10.0.2.11Add a custom health probe.
az network application-gateway probe create -g agw-lab-rg \ --gateway-name web-agw -n api-probe --protocol Http --path /health \ --host 127.0.0.1Note the probe path
/health— the backend must actually serve 200 on that path or it'll be marked unhealthy (see exercise 7).Add path-based routing. Send
/api/*toapi-pool, everything else to the default pool:az network application-gateway url-path-map create -g agw-lab-rg \ --gateway-name web-agw -n pathmap --paths "/api/*" \ --address-pool api-pool \ --default-address-pool appGatewayBackendPool \ --http-settings appGatewayBackendHttpSettings \ --default-http-settings appGatewayBackendHttpSettingsYou'd then create a path-based routing rule that uses this map. > Verify:
az network application-gateway url-path-map list -g agw-lab-rg --gateway-name web-agw -o tableshowspathmap.Enable the WAF in Detection mode first.
az network application-gateway waf-config set -g agw-lab-rg \ --gateway-name web-agw --enabled true --firewall-mode Detection \ --rule-set-type OWASP --rule-set-version 3.2Detection logs would-be blocks without breaking anything — the right way to find false positives before enforcing. Then switch to enforcing:
az network application-gateway waf-config set -g agw-lab-rg \ --gateway-name web-agw --enabled true --firewall-mode Prevention \ --rule-set-type OWASP --rule-set-version 3.2Diagnose and fix: all backends unhealthy (probe path returns 404). This is App Gateway's signature failure. Your probe checks
/health, but the backend app only serves/. The probe gets a 404, marks every backend unhealthy, and clients get 502 Bad Gateway from the frontend even though the app is up. Diagnose:az network application-gateway show-backend-health -g agw-lab-rg -n web-agwshows the pool
Unhealthywith a reason like "received 404". Fix: point the probe at a path the backend actually serves (or add a/healthroute to the app):az network application-gateway probe update -g agw-lab-rg \ --gateway-name web-agw -n api-probe --path /Verify: after the probe interval,
show-backend-healthflips the pool toHealthyand the frontend stops returning 502. Lesson: App Gateway returns 502 when no backend is probe-healthy; a probe path the backend doesn't serve is the usual cause — distinct from the backend being down.Cleanup — do not skip. The gateway bills hourly + capacity units. Delete the entire group now:
az group delete --name agw-lab-rg --yes --no-waitVerify:
az group show -n agw-lab-rgeventually returns not-found. Double-check in the portal's Cost Management that no App Gateway lingers.
Independent challenge
Combine this module with module 04 (Load Balancer) and articulate the
division of labor. Deploy a small HTTP backend (two az container create
instances or two tiny VMs serving different content on / and /api), front
them with an Application Gateway doing path-based routing (/api/* to one
pool, everything else to another) with a health probe that matches what the
backends actually serve, and enable the WAF in Detection mode. Then explain, in
writing, exactly which parts of this design an L4 Azure Load Balancer could
not do and why you needed L7. Delete the resource group the moment you finish
— the gateway is billing the entire time it exists.
Stuck? One hint
Path-based routing (/api/* vs /) requires reading the URL, which lives at
Layer 7 — an L4 Load Balancer sees only IP and port and can't distinguish
paths, so it physically cannot route by URL, terminate TLS to inspect content,
or run a WAF. Make sure your probe path returns 200 from the backends, or every
pool shows unhealthy and you get 502s regardless of the routing config.
Common mistakes & troubleshooting
- Probe path mismatch → 502. The most common App Gateway failure: the probe
hits a path the backend doesn't serve (or wrong host/port), all backends go
unhealthy, and clients get 502. Check
show-backend-healthfirst. - Not giving App Gateway its own subnet. It requires a dedicated subnet; sharing one with other resources fails or is unsupported.
- Using a Basic public IP. v2 gateways require a Standard SKU public IP.
- Turning on WAF Prevention blind. Go through Detection mode first to catch false positives; enforcing straight away can block legitimate traffic.
- Confusing NSG and WAF. An NSG filters L3/L4 (IP/port) and can't see HTTP; the WAF filters L7 request content. You often want both.
- Cost pitfall (the big one): Standard_v2 and WAF_v2 bill a fixed hourly charge plus capacity units whether or not any traffic flows. An idle gateway left over a weekend is real money. Provisioning also takes minutes, so people leave them up "to save time" — don't. Delete the group as soon as the exercise is done.
Checkpoint quiz
Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.
- Give three things Application Gateway can do that the L4 Azure Load Balancer cannot, and say why (what layer).
- Your App Gateway frontend returns 502 Bad Gateway but the backend app is running fine when hit directly. What's the most likely cause and how do you confirm?
- What is the difference between WAF Detection and Prevention mode, and which should you enable first?
- Why must Application Gateway have its own dedicated subnet?
- What does "TLS termination at the gateway" enable that end-to-end pass-through TLS to the backend would not?
- Which tier gives you the Web Application Firewall, and what's the cost implication of running it idle?
- How does the WAF differ from an NSG in what it inspects?
Show answers
- Path/URL-based routing, host header-based routing, TLS termination, and a WAF — all require reading Layer-7 (HTTP) content, which the L4 LB (transport layer) can't see.
- No backend is probe-healthy — usually the probe targets a path/port/host the
backend doesn't serve, so it's marked unhealthy and the gateway has nowhere
to send traffic. Confirm with
az network application-gateway show-backend-health. - Detection logs rule matches but blocks nothing; Prevention actively blocks. Enable Detection first to find false positives, then switch to Prevention.
- It needs an exclusive subnet for its own instances/infrastructure; sharing the subnet with other resources isn't supported.
- Terminating TLS lets the gateway decrypt and inspect the request, which is required for path-based routing and the WAF to work; pure pass-through would hide the content from the gateway.
- The WAF_v2 tier. It bills a fixed hourly charge plus capacity units even when idle — leaving it running costs money regardless of traffic.
- The WAF inspects L7 HTTP request content against OWASP rules (SQLi, XSS, etc.); an NSG filters L3/L4 on IP/port/protocol and has no HTTP awareness.
Next
07 — Azure Firewall & hub-spoke: centralize egress control with route tables and assemble the full hub-and-spoke topology.