Secure a Web App with Azure WAF v2

Deploy an Application Gateway with WAF v2 to protect and load balance a web app.

Introduction

30 Second Summary

Every time you visit a website, your request travels through layers of security before reaching the actual server. Without these protections, attackers can exploit vulnerabilities to steal data or take down entire services.

In this project, you will build a production-style secure web application architecture on Azure. You will design a network with isolated segments, lock down backend servers, deploy a firewall that actively blocks malicious traffic, and configure DNS for name resolution.

What You'll Build

A multi-tier secure web application architecture using Azure Virtual Networks, Network Security Groups, Application Gateway with WAF v2, and Azure DNS.

By the end of this project, you'll have:

  • A Virtual Network with dedicated subnets isolating your Application Gateway from backend servers.
  • Network Security Groups with custom security rules that block direct internet access to your backend VMs.
  • An Application Gateway with WAF v2 that load balances traffic and blocks SQL injection and XSS attacks using OWASP rules.
  • An Azure DNS zone resolving a domain name to the Application Gateway public IP.
  • Secret Mission: Write custom WAF rules to block traffic from specific IP ranges and user agents.

Are there any prerequisites?

You need an Azure pay-as-you-go account to complete this project. This project costs approximately $0.50 to $1.00 if you delete all resources within an hour of starting.

Set Up the Virtual Network and Subnets

Every secure web application needs a network foundation that separates public-facing traffic from private backend servers. Without this separation, anyone on the internet could reach your servers directly.

In this step, you will create a Virtual Network with dedicated subnets and deploy two backend VMs that are completely hidden from the public internet. This is the network foundation that the rest of your architecture will build on.

In this step, get ready to:
  • Create a resource group and Virtual Network with planned IP address ranges.
  • Create dedicated subnets to separate gateway traffic from backend servers.
  • Deploy two backend VMs that are hidden from direct internet access.
Create a resource group and Virtual Network

A resource group is a container that holds all related Azure resources together. You will create one to keep your entire networking lab organized in a single place.

  • In the Azure Portal search box at the top, type Resource group.
  • Select Resource groups in the search results.
  • Select + Create.
  • On the Basics tab, select your subscription.
  • For Resource group, enter myNetworkingLab.
  • For Region, select East US.
  • Select Review + create, then select Create.

Now create the Virtual Network that will contain all your subnets.

  • In the search box at the top of the portal, type Virtual network.
  • Select Virtual networks in the search results.
  • Select + Create.
  • On the Basics tab, select your subscription.
  • For Resource group, select myNetworkingLab.
  • For Name, enter myVNet.
  • For Region, select East US.
  • Select Next to proceed to the Security tab.
  • Leave the defaults on the Security tab and select Next to proceed to the IP Addresses tab.
  • In the address space box, verify the address space is set to 10.0.0.0/16.
  • Do not create the VNet yet. You will add subnets in the next substep before clicking Create.

What is CIDR notation?

CIDR notation like 10.0.0.0/16 defines the size of your network. The /16 means the first 16 bits are fixed, giving you 65,536 available IP addresses for the entire network.

Think of it like a postal code system. The /16 is the city, and each /24 subnet is a street within that city with 256 addresses.

Create dedicated subnets with proper segmentation

You need two subnets inside your VNet: one exclusively for the Application Gateway and one for your backend servers. Keeping them in separate subnets creates a security boundary between the components.

While still on the IP Addresses tab of the Create virtual network wizard, configure your first subnet.

  • In the Subnets area, select the default subnet that appears.
  • In the Edit subnet pane, change the Name to myAGSubnet.
  • Leave the Starting address as 10.0.0.0.
  • Leave the Subnet size as /24 (256 addresses).
  • Select Save.

Now add the second subnet for the backend VMs.

  • Select + Add a subnet.
  • For Name, enter myBackendSubnet.
  • For Starting address, enter 10.0.1.0.
  • Leave the Subnet size as /24 (256 addresses).
  • Select Add.
  • Select Review + create at the bottom of the screen.
  • When validation passes, select Create.

Why separate subnets?

Each subnet acts as a security boundary. The myAGSubnet (10.0.0.0/24) can ONLY contain application gateways. This is an Azure-enforced restriction.

The myBackendSubnet (10.0.1.0/24) holds your backend VMs. Later, you will attach a Network Security Group to this subnet to control exactly which traffic can reach your servers.

Wait for the VNet deployment to complete. You should see a notification confirming the deployment succeeded.

VNet creation failed?

Make sure the address ranges do not overlap. myAGSubnet should start at 10.0.0.0 and myBackendSubnet should start at 10.0.1.0. If you accidentally typed the same starting address for both, Azure will reject the configuration.

Also confirm you selected the myNetworkingLab resource group and East US region. help me fix my Virtual Network creation error

Deploy two backend VMs

Your backend VMs will serve web pages through IIS (Internet Information Services). These VMs will have no public IP addresses, making them invisible to the internet. Only the Application Gateway subnet will be able to reach them.

  • In the search box at the top of the portal, type Virtual machines.
  • Select Virtual machines in the search results.
  • Select + Create, then select Virtual machine from the dropdown.

Configure the Basics tab for your first VM.

  • For Resource group, select myNetworkingLab.
  • For Virtual machine name, enter myVM1.
  • For Region, select East US.
  • For Image, select a Windows Server image (such as Windows Server 2022 Datacenter).
  • For Size, select Standard_B1s. You may need to click See all sizes to find it.
  • Under Administrator account, enter a username and a strong password. Remember these credentials for later.
  • Under Inbound port rules, select None for Public inbound ports.

Configure the Networking tab.

  • Select the Networking tab at the top.
  • For Virtual network, select myVNet.
  • For Subnet, select myBackendSubnet (10.0.1.0/24).
  • For Public IP, select None.

Why no public IP?

Setting the public IP to None means this VM cannot be reached directly from the internet. The only way traffic will reach these servers is through the Application Gateway in myAGSubnet, which you will set up in a later step.

This is a core principle of secure architecture: backend servers should never be directly exposed to the internet.

Now install IIS automatically using the Custom Script Extension.

  • Select the Advanced tab at the top.
  • Under Extensions, select Select an extension to install.
  • Search for and select Custom Script Extension, then select Next.
  • In the Command field (or commandToExecute setting), enter:
powershell Add-WindowsFeature Web-Server; powershell Add-Content -Path "C:\inetpub\wwwroot\Default.htm" -Value $($env:computername)

What does this command do?

This PowerShell command does two things. First, Add-WindowsFeature Web-Server installs IIS on the VM so it can serve web pages.

Second, it writes the VM's hostname into the default web page. This will help you verify load balancing is working later, because each VM will display its own name.

  • Select Create (or OK) to save the extension.
  • Select Review + create at the bottom of the page.
  • When validation passes, select Create.

Wait for myVM1 to finish deploying, then repeat the same steps to create a second VM.

  • Follow the same process as above, but set the Virtual machine name to myVM2.
  • Use the same settings: myNetworkingLab resource group, East US region, Standard_B1s size, myBackendSubnet, no public IP, same Custom Script Extension command.
  • Select Review + create, then Create.

VM deployment takes a few minutes

Each VM takes a few minutes to provision. You can start creating myVM2 while myVM1 is still deploying. Azure handles them in parallel.

After both VMs have finished deploying, verify their configuration.

  • In the search box, type Virtual machines and select Virtual machines.
  • Select myVM1 to open its overview page.
  • Confirm the Public IP address field shows a dash or is empty (no public IP assigned).
  • Under Networking in the left menu, confirm the VM is in myBackendSubnet with a private IP in the 10.0.1.x range.
  • Repeat for myVM2.

Don't see your VMs in myBackendSubnet?

If a VM ended up in the wrong subnet, you may have selected myAGSubnet instead of myBackendSubnet during creation. Delete the VM and recreate it, making sure to select myBackendSubnet (10.0.1.0/24) on the Networking tab.

If you see a public IP assigned, you forgot to set Public IP to None on the Networking tab. Delete the VM and recreate it with the correct setting. help me fix my VM networking configuration

Your network foundation is ready. You have a VNet with two isolated subnets and two backend servers that cannot be reached directly from the internet. Next up, you will lock down the backend subnet even further with Network Security Groups.

Secure the Backend with Network Security Groups

In Step 1, you built a Virtual Network with two subnets and deployed backend VMs that have no public IP addresses. That alone is not enough to protect them.

Without traffic rules, any resource inside the VNet can still reach the backend VMs on any port. In this step, you will create a Network Security Group (NSG) that acts as a firewall at the subnet level, allowing only the traffic you explicitly permit.

In this step, get ready to:
  • Create an NSG with inbound rules that allow HTTP only from the Application Gateway subnet.
  • Add an outbound rule and associate the NSG with your backend subnet.
  • Verify that your VMs are not directly accessible from the internet.
Create an NSG and define inbound security rules

A Network Security Group contains a list of security rules that allow or deny traffic based on source, destination, port, and protocol. Each rule has a priority number that determines the order Azure evaluates it.

  • In the Azure Portal search box at the top, type Network security group.
  • Select Network security groups in the search results.
  • Click + Create.
  • On the Basics tab, select your subscription.
  • For Resource group, select myNetworkingLab.
  • For Network security group name, enter myBackendNSG.
  • For Region, select East US.
  • Click Review + create.
  • After validation passes, click Create.

What is an NSG?

A Network Security Group is a set of firewall rules that Azure evaluates for every packet entering or leaving a subnet (or network interface). When you associate an NSG with a subnet, its rules apply to every resource inside that subnet automatically.

Now add the first inbound rule to allow HTTP traffic only from the Application Gateway subnet.

  • Once the NSG deploys, click Go to resource to open myBackendNSG.
  • In the left menu under Settings, select Inbound security rules.
  • Click + Add.
  • Set Source to IP Addresses.
  • In Source IP addresses/CIDR ranges, enter 10.0.0.0/24.
  • Set Destination port ranges to 80.
  • Set Protocol to TCP.
  • Set Action to Allow.
  • Set Priority to 100.
  • For Name, enter AllowHTTPFromAGSubnet.
  • Click Add.

Why 10.0.0.0/24 as the source?

The address range 10.0.0.0/24 is the Application Gateway subnet (myAGSubnet). By restricting HTTP traffic to this source, the backend VMs only accept requests that come through the gateway.

Direct internet traffic to port 80 on the backend is blocked because it does not originate from 10.0.0.0/24.

Now add a second inbound rule to deny all other internet traffic.

  • Click + Add again.
  • Set Source to Service Tag.
  • Set Source service tag to Internet.
  • Set Destination port ranges to *.
  • Set Protocol to Any.
  • Set Action to Deny.
  • Set Priority to 200.
  • For Name, enter DenyAllInboundInternet.
  • Click Add.

How does rule priority work?

Azure evaluates NSG rules in priority order, starting with the lowest number. A rule with priority 100 is evaluated before a rule with priority 200.

Once a matching rule is found, Azure stops processing further rules. This means your Allow rule at priority 100 takes effect before the Deny rule at priority 200 for HTTP traffic from the gateway subnet.

Don't see the rule appear?

Make sure you clicked Add (not just filled in the form). The rule should appear in the inbound rules list immediately after saving.

If the Source IP addresses/CIDR ranges field is greyed out, confirm that Source is set to IP Addresses, not a service tag.

help me troubleshoot my NSG inbound rule not appearing

Create outbound security rules and associate the NSG

Your VMs need outbound internet access so Windows can download updates. You will add an outbound Allow rule, then associate the NSG with the backend subnet.

  • In the left menu under Settings, select Outbound security rules.
  • Click + Add.
  • Set Destination to Service Tag.
  • Set Destination service tag to Internet.
  • Set Destination port ranges to *.
  • Set Protocol to Any.
  • Set Action to Allow.
  • Set Priority to 100.
  • For Name, enter AllowInternetOutbound.
  • Click Add.

Now associate the NSG with your backend subnet.

  • In the left menu under Settings, select Subnets.
  • Click + Associate.
  • Under Associate subnet, select myVNet for Virtual network.
  • Select myBackendSubnet for Subnet.
  • Click OK.

You should now see myBackendSubnet listed under the Subnets section of your NSG.

Why associate at the subnet level?

When you associate an NSG with a subnet, its rules apply to every resource inside that subnet automatically. This means both myVM1 and myVM2 are now protected by the same rules without needing per-VM configuration.

NSG not showing in the subnet list?

Make sure you selected myVNet (not another VNet) in the Virtual network dropdown. The NSG must be in the same region and subscription as the VNet.

help me troubleshoot associating my NSG with a subnet

Verify traffic is blocked

Your VMs have no public IP addresses, and the NSG now explicitly denies all inbound internet traffic except HTTP from the gateway subnet. Let's verify this by reviewing the effective security rules.

  • In the Azure Portal search box, type myVM1 and select the VM from the results.
  • In the left menu, expand Networking and select Network settings.
  • Select the network interface name (the NIC attached to the VM).
  • Under Help, select Effective security rules.

You should see your custom rules (AllowHTTPFromAGSubnet at priority 100 and DenyAllInboundInternet at priority 200) alongside the Azure default rules.

What are default rules?

Azure creates several default rules in every NSG that you cannot delete. These include AllowVnetInBound (allows traffic within the VNet), AllowAzureLoadBalancerInBound, and DenyAllInBound at very low priority (65500).

Your custom rules override the defaults because they have a higher priority (lower number). The default DenyAllInBound at priority 65500 is a safety net, but your explicit Deny at 200 catches internet traffic earlier.

  • Confirm that no public IP address is listed on the VM's overview page.
  • Verify that the effective inbound rules show HTTP (port 80) allowed only from source 10.0.0.0/24.
  • Verify that all other inbound internet traffic is denied by your DenyAllInboundInternet rule.

VM must be running to view effective rules

Azure only shows effective security rules when the VM is in a running state. If you see an error or empty results, go to the VM's overview page and click Start if the VM is deallocated.

help me view effective security rules for my Azure VM

Your backend is now locked down. Only traffic arriving from the Application Gateway subnet on port 80 can reach your VMs. Next up, you will deploy the Application Gateway with WAF v2 to actually route and protect that traffic.

Deploy Application Gateway with WAF v2

Your backend VMs are now locked down behind the NSG, invisible to the public internet. The next challenge is giving users a way to reach those servers without exposing them directly.

The solution is an Application Gateway with WAF v2. This service sits in its own subnet, accepts traffic from the internet, inspects every request for threats, and load balances healthy requests across your backend VMs.

In this step, get ready to:
  • Create an Application Gateway with WAF v2 tier and a public IP frontend.
  • Configure a backend pool, HTTP settings, listener, and routing rule.
  • Verify load balancing is working by browsing to the public IP.
Create the Application Gateway with WAF v2 tier

The Application Gateway creation wizard walks you through several tabs: Basics, Frontends, Backends, and Configuration. You will set up the gateway itself first, then wire it to your backend VMs.

  • In the Azure Portal search bar, type Application Gateway and select Application Gateways from the results.
  • Click + Create and select Application Gateway.

You are now on the Basics tab.

  • Set Resource group to myNetworkingLab.
  • Enter myAppGateway for Application gateway name.
  • Set Region to East US.
  • Set Tier to WAF V2.
  • Next to WAF Policy, click Create new.
  • Enter myWAFPolicy as the policy name and click OK.
  • Under Configure virtual network, set Virtual network to myVNet.
  • Set Subnet to myAGSubnet (10.0.0.0/24).
  • Click Next: Frontends.

What is WAF V2?

WAF V2 is the current generation of Azure's Web Application Firewall for Application Gateway. It inspects every HTTP request for common web attack patterns like SQL injection and cross-site scripting using the OWASP Core Rule Set.

Selecting WAF V2 as the tier bundles the firewall directly into the gateway. The WAF policy you just created holds the rule configuration and can be shared across multiple gateways if needed.

You are now on the Frontends tab.

  • Verify Frontend IP address type is set to Public.
  • Click Add new next to Public IP address.
  • Enter myAGPublicIP as the name and click OK.
  • Click Next: Backends.

Why a Standard SKU Static IP?

Application Gateway v2 always creates a Standard SKU public IP with static allocation. A static IP means the address never changes, even if you stop and restart the gateway.

This matters because your DNS records will point to this IP later. If the IP changed on restart, all DNS records would break.

Configure the backend pool and routing

The Backends and Configuration tabs wire the gateway to your VMs. You will define which VMs receive traffic and how the gateway communicates with them.

  • On the Backends tab, click Add a backend pool.
  • Enter myBackendPool for Name.
  • Under Target type, select IP address or FQDN.
  • Enter 10.0.1.4 as the first target (this is myVM1).
  • Enter 10.0.1.5 as the second target (this is myVM2).
  • Click Add to save the backend pool.
  • Click Next: Configuration.

You are now on the Configuration tab. This is where you connect the frontend to the backend pool using a routing rule.

  • Click Add a routing rule in the Routing rules column.
  • Enter myRoutingRule for Rule name.
  • Enter 100 for Priority.

You are now on the Listener tab inside the routing rule window.

  • Enter myListener for Listener name.
  • Set Frontend IP to Public IPv4.
  • Leave Port set to 80.
  • Leave Protocol set to HTTP.
  • Click the Backend targets tab at the top of the routing rule window.
  • Set Backend target to myBackendPool.
  • Next to Backend settings, click Add new.
  • Enter myHTTPSetting for the Backend settings name.
  • Set Backend port to 80.
  • Set Backend protocol to HTTP.
  • Verify Request time-out (seconds) is set to 20.
  • Click Add to save the backend settings.
  • Click Add to save the routing rule.

What does routing do here?

The routing rule connects three pieces: the listener (which accepts traffic on port 80 at the public IP), the backend pool (your two VMs), and the HTTP settings (how the gateway communicates with the VMs).

When a user browses to the public IP, the listener catches the request. The routing rule then forwards it to one of the backend VMs using the protocol and port defined in the HTTP settings.

You are back on the Configuration tab.

  • Click Next: Tags.
  • Click Next: Review + create.
  • Review your settings and click Create.

Deployment takes approximately 10 minutes

Application Gateway creation takes 10 minutes or longer to complete. You can monitor progress on the deployment page. Wait until the deployment finishes before moving to the next substep.

Verify load balancing is working

Now that the gateway is deployed, you can confirm it is distributing traffic to your backend VMs.

  • Navigate to Application Gateways in the Azure Portal and select myAppGateway.
  • On the Overview page, confirm the status shows Running.
  • Find the Frontend public IP address on the Overview page and copy it.
  • Open a new browser tab and paste the IP address into the address bar.
  • Press Enter.

You should see the IIS default welcome page. This confirms the Application Gateway is routing traffic through to your backend VMs.

  • Refresh the page several times.

The Application Gateway load balances across both myVM1 and myVM2. Although both VMs serve the same default IIS page, the gateway distributes requests between them behind the scenes.

Not seeing the IIS page?

  • Confirm the Application Gateway status is Running on the Overview page. If it still shows provisioning, wait a few more minutes.
  • Check that your backend pool targets are 10.0.1.4 and 10.0.1.5. A typo in the IP addresses means the gateway cannot reach the VMs.
  • Verify your NSG allows HTTP from 10.0.0.0/24 (the gateway subnet). If this rule is missing, the gateway's health probes will fail.

Help me troubleshoot my Application Gateway not reaching the backend VMs.

Why does this prove the architecture works?

Your backend VMs have no public IP addresses. The only way to reach them from the internet is through the Application Gateway sitting in myAGSubnet.

The NSG on myBackendSubnet allows HTTP traffic only from 10.0.0.0/24 (the gateway's subnet). If someone tried to access the VMs directly, the NSG would block them. Traffic must flow through the gateway, which means the WAF inspects every single request.

Your Application Gateway is live and load balancing traffic across both backend VMs. Next up, you will configure the WAF policy to actively block malicious requests like SQL injection and cross-site scripting attacks.

Configure WAF Policy and Test Traffic Filtering

Your Application Gateway is live and load balancing traffic across both backend VMs. But right now, the WAF policy is only watching. It logs suspicious requests without actually stopping them.

In this step, you will activate the WAF's defenses by switching to Prevention mode. Then you will simulate real-world attacks to prove that the WAF blocks malicious traffic before it reaches your servers.

In this step, get ready to:
  • Review managed rules and switch the WAF to Prevention mode.
  • Test WAF blocking with SQL injection and XSS attack simulations.
  • Review WAF logs to understand which rules triggered and why.
Review managed rules and switch to Prevention mode

Your WAF policy currently runs in Detection mode. This means it logs any request that matches a security rule but lets the traffic through anyway. To actively block threats, you need to switch to Prevention mode.

  • In the Azure Portal search bar, type myWAFPolicy and select it from the results.
  • In the left menu, click Managed rules.
  • Confirm that the OWASP Core Rule Set (CRS) 3.2 is listed with all rule groups active (SQL injection, XSS, LFI, RFI, and more).

What is the OWASP Core Rule Set?

The OWASP Core Rule Set (CRS) is a collection of generic attack detection rules maintained by the Open Web Application Security Project. Version 3.2 covers common web attack categories including SQL injection, cross-site scripting (XSS), local file inclusion (LFI), and remote file inclusion (RFI).

These managed rules are included at no additional cost with your WAF policy. Azure keeps them updated so you always have protection against the latest known attack patterns.

  • In the left menu, click Policy settings.
  • Change the Mode from Detection to Prevention.
  • Click Save.

What is the difference between Detection and Prevention mode?

In Detection mode, the WAF monitors and logs requests that match rules but does not block them. The request still reaches your backend servers.

In Prevention mode, the WAF actively blocks matching requests and returns a 403 Forbidden response to the attacker. The blocked request never reaches your backend VMs.

Your WAF policy page should now show the mode as Prevention. The managed rules will start blocking any request that triggers a security rule.

Don't see the Policy settings option?

Make sure you navigated directly to myWAFPolicy (the WAF policy resource), not to the Application Gateway resource. The mode setting lives on the WAF policy itself.

Help me find the Policy settings blade in my WAF policy.

Test WAF blocking a SQL injection attack

Now that Prevention mode is active, you can prove it works by sending requests that look like real attacks. The WAF will inspect the query string and block anything that matches a known attack pattern.

  • Return to myAppGateway in the portal and copy the public IP address from the Overview page.
  • Open a new browser tab and navigate to your Application Gateway public IP with this SQL injection payload appended:
http://[your-app-gateway-ip]/?id=1 OR 1=1

What is this attack simulating?

The query string ?id=1 OR 1=1 is a classic SQL injection attempt. An attacker adds this to trick a database query into returning all records instead of one. The WAF's OWASP CRS 3.2 rules recognize this pattern and block it instantly.

You should see a 403 Forbidden response in your browser. This confirms the WAF blocked the SQL injection attempt.

  • Now test a cross-site scripting (XSS) attack by navigating to:
http://[your-app-gateway-ip]/?q=<script>alert('xss')</script>

This should also return a 403 Forbidden response. The WAF detected the <script> tag in the query string and blocked it as an XSS attempt.

Why does the WAF block script tags?

Cross-site scripting (XSS) attacks inject malicious JavaScript into web pages. When another user views the page, the script executes in their browser. It can steal cookies, session tokens, or redirect users to malicious sites.

The WAF's XSS rule group catches common patterns like <script> tags, event handlers, and JavaScript URIs in query strings, headers, and request bodies.

Still seeing the IIS page instead of 403?

If your test requests return the normal IIS page instead of a 403 Forbidden, double-check that you saved the mode change in the WAF policy. Navigate back to myWAFPolicy and confirm the mode shows Prevention under Policy settings.

Also allow a minute or two for the policy change to take effect across the Application Gateway instances.

My WAF is in Prevention mode but SQL injection test still shows the IIS page.

Review WAF logs and understand the block

Seeing the 403 page proves the WAF is blocking attacks. Now you will look at the WAF logs to understand exactly which rule triggered, what pattern it matched, and what action was taken.

  • In the Azure Portal, navigate to myAppGateway.
  • In the left menu under Monitoring, click Diagnostic settings.
  • Click Add diagnostic setting.
  • Enter a name for the setting (for example, waf-logs).
  • Under Logs, check the box for ApplicationGatewayFirewallLog.
  • Under Destination details, check Send to Log Analytics workspace.
  • If you do not have a Log Analytics workspace, click Create New and accept the defaults to create one in East US.
  • Click Save.

Why enable diagnostic settings?

WAF firewall logs are not collected by default. You must enable a diagnostic setting and route the logs to a destination like Log Analytics. Once enabled, every request the WAF evaluates, matches, or blocks is recorded with details about the triggering rule.

  • After saving, re-run both attack tests in your browser (the SQL injection and XSS URLs from the previous substep) so the logs capture fresh entries.
  • Wait 3-5 minutes for the logs to appear in Log Analytics.
  • Return to myAppGateway and in the left menu under Monitoring, click Logs.
  • Close any sample query dialogs that appear.
  • In the query editor, paste the following query and click Run:
AzureDiagnostics 
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "ApplicationGatewayFirewallLog"
| project TimeGenerated, clientIp_s, requestUri_s, ruleId_s, message_s, action_s
| order by TimeGenerated desc
| limit 20

What do these log fields mean?

  • ruleId identifies which specific OWASP rule matched (for example, rule 942130 detects SQL injection patterns like 1=1).
  • message is the human-readable description of what the rule detected.
  • action shows what the WAF did. In Prevention mode, you will see Blocked for requests that were stopped and Matched for individual rule matches before the final blocking decision.
  • requestUri shows the exact URL that was requested, including the malicious payload.

You should see log entries showing your SQL injection and XSS test requests with Blocked actions and specific rule IDs that triggered the block.

No log entries appearing?

Firewall logs can take 5-10 minutes to appear in Log Analytics after you enable the diagnostic setting. Make sure you re-ran the attack tests after enabling diagnostics. Also verify you selected ApplicationGatewayFirewallLog in your diagnostic setting (not just the Access log).

Help me troubleshoot missing WAF log entries in Log Analytics.

Your WAF is now actively protecting your backend servers. Every malicious request is blocked, logged, and traceable to a specific OWASP rule. Next up, you will configure Azure DNS to give your Application Gateway a proper domain name.

Configure Azure DNS

Your Application Gateway is now load balancing traffic and your WAF is actively blocking malicious requests. The architecture is working, but users still access it via a raw IP address.

The final piece is DNS name resolution. Azure DNS lets you map a human-readable domain name to your Application Gateway's public IP, so users type a URL instead of memorizing numbers.

In this step, get ready to:
  • Create an Azure DNS zone for your web application.
  • Add an A record that points your domain to the Application Gateway.
Create an Azure DNS zone

A DNS zone holds all the DNS records for a domain. You will create a zone for a demo domain that represents how production DNS works on Azure.

  • In the Azure Portal search bar at the top, type DNS zones and select DNS zones from the results.
  • Click + Create.
  • On the Basics tab, select your subscription from the Subscription dropdown.
  • For Resource group, select myNetworkingLab.
  • For Name, enter mywebapp.contoso.com.
  • Click Review + create, then click Create.
  • When deployment completes, click Go to resource.

The Overview page for your DNS zone appears. You should see four Azure name servers listed (Name server 1 through Name server 4) along with default NS and SOA record sets.

What are these name servers?

Azure assigns four name servers to every DNS zone. In a production scenario, you would update your domain registrar to point to these servers so the internet knows Azure handles DNS for your domain.

For this lab you are using a demo domain (contoso.com), so you do not need to update a registrar. The configuration pattern is the same either way.

  • Make a note of the four name server values on the Overview page.

Don't see the DNS zone?

Make sure you selected the correct resource group (myNetworkingLab) during creation. If the deployment failed, check that the zone name is unique within your subscription.

help me troubleshoot my Azure DNS zone creation

Add an A record pointing to Application Gateway

An A record maps a hostname to an IP address. You will create an alias A record that dynamically links to your Application Gateway's public IP resource rather than a static IP value.

  • On the Overview page of your mywebapp.contoso.com DNS zone, click the + Record set button.
  • In the Add record set pane, enter www in the Name field.
  • For Type, select A.
  • For Alias record set, select Yes.
  • For Alias type, select Azure resource.
  • For Azure resource, select the myAGPublicIP public IP address from the list.
  • Click OK to create the record.

You should now see a www A record in your DNS zone's record sets list.

Why use an alias record instead of a static IP?

An alias record points to the Azure resource itself, not just its IP address. If the Application Gateway's public IP ever changes (for example, after a redeployment), the DNS record automatically updates.

This prevents dangling DNS records that point to incorrect IP addresses.

How does DNS resolution work in this architecture?

When a user browses to www.mywebapp.contoso.com, the DNS query resolves to your Application Gateway's public IP.

The Application Gateway receives the request, the WAF inspects it for threats, and then the gateway load balances it across your backend VMs (myVM1 and myVM2). The full chain is: Client -> DNS -> Application Gateway (WAF + Load Balancer) -> Backend VMs.

Don't see myAGPublicIP in the resource list?

The public IP resource must be Standard SKU to appear as an alias target. Confirm that myAGPublicIP was created with Standard SKU in Step 3.

If the resource does not appear, wait a few minutes and refresh the portal page. It can take up to 15 minutes for recently deployed resources to propagate.

help me find my public IP resource for the alias record

Secret mission

Write Custom WAF Rules

Your managed OWASP rules are catching known attack patterns, but what about threats specific to your application? In this secret mission, you will author custom WAF rules that block traffic from suspicious user agents and specific IP ranges. This takes you from relying on pre-built rulesets to writing targeted security logic of your own.

Clean Up Your Resources

Clean Up Your Resources

This project uses paid Azure resources that charge by the hour. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Cost warning

Your Application Gateway WAF v2 charges $0.443 per hour even when no traffic is flowing. The two VMs add approximately $0.01 per hour each. A partial hour is billed as a full hour.

If you leave everything running, you will spend approximately $11 per day. Delete your resources as soon as you finish the project.

Resources you used:

  • Application Gateway (myAppGateway) with WAF v2 tier. Costs $0.443/hour.
  • 2 Windows Server VMs (myVM1 and myVM2). Cost approximately $0.01/hour each.
  • Public IP address (myAGPublicIP). Cost approximately $0.005/hour.
  • Virtual Network (myVNet), subnets, NSG (myBackendNSG), DNS zone, and WAF policy. Free.
  • Resource group (myNetworkingLab) containing all of the above.

Keep everything running

No action needed. Choose this if you are still actively experimenting with WAF rules or testing traffic patterns.

  • Your resources will continue running and charging approximately $0.47 per hour (about $11 per day).
  • You can return to the Azure Portal at any time to continue working with your Application Gateway and WAF policy.
  • When you are done experimenting, come back to this section and follow the Delete tab.

Pause - I'll come back to this later

Deallocate your VMs to stop their billing. The Application Gateway cannot be paused and will continue charging $0.443 per hour.

  • In the Azure Portal, navigate to Virtual machines.
  • Select myVM1, then click Stop in the top toolbar.
  • Confirm the deallocation when prompted.
  • Repeat for myVM2.
  • The Application Gateway will still charge $0.443 per hour while your VMs are stopped. For full cost savings, use the Delete tab instead.

Delete - I don't want to use this again

Remove all project resources in one action by deleting the resource group. This stops all billing immediately.

  • In the Azure Portal, search for Resource groups in the top search bar.
  • Select myNetworkingLab from the list.
  • Click Delete resource group in the top toolbar.
  • Type myNetworkingLab in the confirmation field to confirm deletion.
  • Click Delete.
  • This removes the Application Gateway, both VMs, the VNet, subnets, NSG, public IP, DNS zone, WAF policy, and all other resources within the group. Deletion may take a few minutes to complete.

Nice Work!

Nice Work!

You just built a production-style secure web application architecture on Azure. Your traffic now flows through DNS resolution to an Application Gateway that load balances across backend VMs, with WAF inspecting every request for threats and NSGs providing defense-in-depth at the subnet level.

You've learned how to:

  • Design a multi-subnet Virtual Network with CIDR-based IP addressing and secure the backend using Network Security Groups with priority-based inbound and outbound rules.
  • Deploy an Application Gateway with WAF v2 that load balances traffic across backend servers while actively blocking SQL injection and XSS attacks using OWASP CRS 3.2 managed rules in Prevention mode.
  • Configure request routing rules and Azure DNS to direct public traffic through the gateway to a private backend pool.
  • Secret Mission: Authored custom WAF rules to block specific user agents and IP ranges, tested them with PowerShell, and verified the WAF log entries.

Ready to quiz yourself?