{"id":21474,"date":"2019-03-06T13:27:03","date_gmt":"2019-03-06T13:27:03","guid":{"rendered":"https:\/\/aidanfinn.com\/?p=21474"},"modified":"2019-03-06T13:40:52","modified_gmt":"2019-03-06T13:40:52","slug":"locking-down-network-access-to-the-azure-application-gateway-firewall","status":"publish","type":"post","link":"https:\/\/aidanfinn.com\/?p=21474","title":{"rendered":"Locking Down Network Access to the Azure Application Gateway\/Firewall"},"content":{"rendered":"<p>In this post, I will explain how you can use a Network Security Group (NSG) to completely lock down network access to the subnet that contains an Azure Web Application Gateway (WAG)\/Web Application Firewall (WAF).<\/p>\n<p>The stops are as follows:<\/p>\n<ol>\n<li>Deploy a WAG\/WAF to a dedicated subnet.<\/li>\n<li>Create a Network Security Group (NSG) for the subnet.<\/li>\n<li>Associate the NSG with the subnet.<\/li>\n<li>Create an inbound rule to allow TCP 65503-65534 from the Internet service tag to the CIDR address of the WAG\/WAF subnet.<\/li>\n<li>Create rules to allow application traffic, such as TCP 443 or TCP 80, from your sources to the CIDR address of the WAG\/WAF<\/li>\n<li>Create a low priority (4000) rule to allow any protocol\/port from the AzureLoadBlanacer service tag to the CIDR address of the WAG\/WAF<\/li>\n<li>Create a rule, with the lowest priority (4096) to Deny All from Any source.<\/li>\n<\/ol>\n<h2>The Scenario<\/h2>\n<p>It is easy to stand up a WAG\/WAF in Azure and get it up and running. But in the real world, you should lock down network access. In the world of Azure, all network security begins with an NSG. When you deploy WAG\/WAF in the real world, you should create an NSG for the WAG\/WAF subnet and restrict the traffic to that subnet to what is just required for:<\/p>\n<ul>\n<li>Health monitoring of the WAG\/WAF<\/li>\n<li>Application access from the authorised sources<\/li>\n<li>Load balancing of the WAG\/WAF instances<\/li>\n<\/ul>\n<p>Everything else inbound will be blocked.<\/p>\n<h2>The NSG<\/h2>\n<p>Good NSG practice is as follows:<\/p>\n<ol>\n<li>Tiers of services are placed into their own subnet. Good news \u2013 the WAG\/WAF requires a dedicated subnet.<\/li>\n<li>You should create an NSG just for the subnet \u2013 name the NSG after the VNet-Subnet, and maybe add a prefix or suffix of NSG to the name.<\/li>\n<\/ol>\n<h2>Health Monitoring<\/h2>\n<p>Azure will need to communicate with the WAG\/WAF to determine the health of the backends \u2013 I know that this sounds weird, but it is what it is.<\/p>\n<p>Note: You can view the health of your backend pool by opening the WAG\/WAF and browsing to Monitoring &gt; Backend Health. Each backend pool member will be listed here. If you have configured the NSG correctly then the pool member status should be \u201cHealthy\u201d, assuming that they are actually healthy. Otherwise, you will get a warning saying:<\/p>\n<blockquote><p>Unable to retrieve health status data. Check presence of NSG\/UDR blocking access to ports 65503-65534 from Internet to Application Gateway.<\/p><\/blockquote>\n<p>OK \u2013 so you need to open those ports from \u201cInternet\u201d. Two questions arise:<\/p>\n<ul>\n<li>Is this secure? Yes \u2013 Microsoft states <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/application-gateway\/application-gateway-diagnostics\">here<\/a> that these ports are \u201c<em>are protected (locked down) by Azure certificates. Without proper certificates, external entities, including the customers of those gateways, will not be able to initiate any changes on those endpoints<\/em>\u201d.<\/li>\n<li>What if my WAG\/WAF is internal and does not have a public IP address? You will still do this \u2013 remember that \u201cInternet\u201d is everything outside the virtual network and peered virtual networks. Azure will communicate with the WAG\/WAF via the Azure fabric and you need to allow this communication that comes from an external source.<\/li>\n<\/ul>\n<p>In my example, my WAF subnet CIDR is 10.0.2.4\/24:<\/p>\n<p><a href=\"\/wp-content\/uploads\/2019\/03\/Allow65503-65534ToAzureWAGWAF.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-21475\" src=\"\/wp-content\/uploads\/2019\/03\/Allow65503-65534ToAzureWAGWAF.png\" alt=\"\" width=\"500\" height=\"621\" srcset=\"https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/Allow65503-65534ToAzureWAGWAF.png 557w, https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/Allow65503-65534ToAzureWAGWAF-241x300.png 241w\" sizes=\"auto, (max-width: 500px) 85vw, 500px\" \/><\/a><\/p>\n<h2>Application Traffic<\/h2>\n<p>Next, I need to allow application traffic. Remember that the NSG operates at the TCP\/UDP level and has no idea of URLs \u2013 that\u2019s the job of the WAG\/WAF. I will use the NSG to define what TCP ports I am allowing into the WAG\/WAF (such as TCP 443) and from what sources.<\/p>\n<p>In my example, the WAF is for internal usage. Clients will connect to applications over a VPN\/ExpressRoute connection. Here is a sample rule:<\/p>\n<p><a href=\"\/wp-content\/uploads\/2019\/03\/AllowTCP443ToWAFFromOnPremises.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-21477\" src=\"\/wp-content\/uploads\/2019\/03\/AllowTCP443ToWAFFromOnPremises.png\" alt=\"\" width=\"500\" height=\"618\" srcset=\"https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/AllowTCP443ToWAFFromOnPremises.png 558w, https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/AllowTCP443ToWAFFromOnPremises-243x300.png 243w\" sizes=\"auto, (max-width: 500px) 85vw, 500px\" \/><\/a><\/p>\n<p>If this was an Internet-facing WAG or WAF, then the source service tag would be Internet. If other services in Azure need to connect to this WAG or WAF, then I would allow traffic from either Virtual Network or specific source CIDRs\/addresses.<\/p>\n<h2>The Azure Load Balancer<\/h2>\n<p>To be honest, this one caught me out until I reasoned what the cause was. My next rule will deny all other traffic to the WAG\/WAF subnet. Without this load balancer rule, the client could not connect to the WAG\/WAF. That puzzled me, and searches led me nowhere useful. And then I realized:<\/p>\n<ul>\n<li>A WAG\/WAF is 1+ instances (2+ in v2), each consuming IP addresses in the subnet.<\/li>\n<li>They are presented to clients as a single IP.<\/li>\n<li>That single IP must be a load balancer<\/li>\n<li>That load balancer needs to probe the load balancer\u2019s own backend pool \u2013 which are the instance(s) of the WAG\/WAF in this case<\/li>\n<\/ul>\n<p>You might ask: isn\u2019t there a default rule to allow a load balancer probe? Yes, it has priority 65001. But we will be putting in a rule at 4096 to prevent all connections, overriding the 65000 rule that allows <em>everything<\/em> from VirtualNetwork \u2013 which includes all subnets in the virtual network and all peered virtual networks.<\/p>\n<p>The rule is simple enough:<\/p>\n<p><a href=\"\/wp-content\/uploads\/2019\/03\/AllowLoadBalancerProbetoAzureWagWaf.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-21476\" src=\"\/wp-content\/uploads\/2019\/03\/AllowLoadBalancerProbetoAzureWagWaf.png\" alt=\"\" width=\"500\" height=\"625\" srcset=\"https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/AllowLoadBalancerProbetoAzureWagWaf.png 551w, https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/AllowLoadBalancerProbetoAzureWagWaf-240x300.png 240w\" sizes=\"auto, (max-width: 500px) 85vw, 500px\" \/><\/a><\/p>\n<h2>Deny Everything Else<\/h2>\n<p>Now we will override the default NSG rules that allow all communications to the subnet from other subnets in the same VNet or peered VNets. This rule should have the lowest possible user-defined priority, which is 4096:<\/p>\n<p><a href=\"\/wp-content\/uploads\/2019\/03\/DenyAllFromAll.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-21478\" src=\"\/wp-content\/uploads\/2019\/03\/DenyAllFromAll.png\" alt=\"\" width=\"558\" height=\"628\" srcset=\"https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/DenyAllFromAll.png 558w, https:\/\/aidanfinn.com\/wp-content\/uploads\/2019\/03\/DenyAllFromAll-267x300.png 267w\" sizes=\"auto, (max-width: 558px) 85vw, 558px\" \/><\/a><\/p>\n<p>Why am I using the lowest possible priority? This is classic good firewall rule practice. General rules should be low priority, and specific rules should be high priority. The more general, the lower. The more specific, the higher. The most general rule we have in firewalls is \u201cblock everything we don\u2019t allow\u201d; in other words, we are creating a white list of exceptions with the previously mentioned rules.<\/p>\n<h2>The Results<\/h2>\n<p>You should end up with:<\/p>\n<ul>\n<li>The health monitoring rule will allow Azure to check your WAG\/WAF over a certificate-secured channel.<\/li>\n<li>Your application rules will permit specified clients to connect to the WAG\/WAF, via a hidden load balancer.<\/li>\n<li>The load balancer can probe the WAG\/WAF and forward client connections.<\/li>\n<li>The low priority deny rule will block all other communications.<\/li>\n<\/ul>\n<p>Job done!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, I will explain how you can use a Network Security Group (NSG) to completely lock down network access to the subnet that contains an Azure Web Application Gateway (WAG)\/Web Application Firewall (WAF). The stops are as follows: Deploy a WAG\/WAF to a dedicated subnet. Create a Network Security Group (NSG) for the &hellip; <a href=\"https:\/\/aidanfinn.com\/?p=21474\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Locking Down Network Access to the Azure Application Gateway\/Firewall&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":18458,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[5],"tags":[316,314,170,242,321,323,320,253,322,190,319,289,281,318,317,315,313],"class_list":["post-21474","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","tag-application-firewall","tag-application-gateway","tag-azure","tag-firewall","tag-health-monitoring","tag-load-balancing","tag-network-security-group","tag-nsg","tag-probe","tag-security","tag-subnet","tag-virtual-network","tag-vnet","tag-waf","tag-wag","tag-web-application-firewall","tag-web-application-gateway"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/aidanfinn.com\/wp-content\/uploads\/2015\/06\/15856883949_20117b0a70_z.jpg","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/posts\/21474","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=21474"}],"version-history":[{"count":1,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/posts\/21474\/revisions"}],"predecessor-version":[{"id":21479,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/posts\/21474\/revisions\/21479"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=\/wp\/v2\/media\/18458"}],"wp:attachment":[{"href":"https:\/\/aidanfinn.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21474"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21474"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aidanfinn.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21474"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}