Application Gateway


The presented resiliency recommendations in this guidance include Application Gateway, Web Application Firewall and associated settings.

Summary of Recommendations

Recommendations Details

AGW-1 - Set a minimum instance count of 2

Category: System Efficiency

Impact: High

Guidance

Azure Application Gateways v2 are always deployed in a highly available fashion, deployed with multiple instances by default regardless of your autoscaling configuration. However, creating a new instance can take up to six or seven minutes. In order to avoid downtime for various failure modes, it is recommended that you configure a minimum instance count of two, ideally with Availability Zone support. By doing this, you will always have at least two instances in your Azure Application Gateway under normal circumstances. If one of them was to have a problem, there will always be another instance present to handle the traffic while a new instance is being created. Also, continue to leverage auto scaling to dynamically scale out based on the traffic requirements without the need of manual intervention.

Resources

Resource Graph Query

// Azure Resource Graph Query
// This query will return all Application Gateways that do not have autoscale enabled or have a min capacity of 1
resources
| where type =~ "microsoft.network/applicationGateways"
| where isnull(properties.autoscaleConfiguration) or properties.autoscaleConfiguration.minCapacity <= 1
| project recommendationId = "agw-1", name, id, tags, param1 = "autoScaleConfiguration: isNull or MinCapacity <= 1"
| order by id asc



AGW-2 - Secure all incoming connections with SSL

Category: Access & Security

Impact: High

Guidance

Ensure that all incoming connections are using HTTPs for production services. Using end to end SSL/TLS or SSL/TLS termination to ensure the security of all incoming connections to the Application Gateway allows you and your users to be safe from possible attacks as it ensures that all data passed between the web server and browsers remain private and encrypted.

Resources

Resource Graph Query

// Azure Resource Graph Query
// You can use the following Azure Resource Graph query to check if an HTTP rule is using an SSL certificate or is using Azure Key Vault to store the certificates
resources
| where type =~ "microsoft.network/applicationGateways"
| mv-expand frontendPorts = properties.frontendPorts
| mv-expand httpListeners = properties.httpListeners
| where isnull(parse_json(httpListeners.properties.sslCertificate))
| project recommendationId="agw-2", name, id, tags, param1=strcat("frontendPort: ", frontendPorts.properties.port), param2="tls: false"



AGW-3 - Enable Web Application Firewall policies

Category: Access & Security

Impact: High

Guidance

Use Application Gateway with Web Application Firewall (WAF) within an application virtual network to protect inbound HTTP/S traffic from the Internet. The WAF provides centralized protection from possible exploits by using rules based on the OWASP (Open Web Application Security Project) core rule sets.

Resources

Resource Graph Query

// Azure Resource Graph Query
// This query will return all Application Gateways that do not have WAF enabled
Resources
| where type =~ "microsoft.network/applicationGateways"
| where properties.firewallpolicy != ""
| project recommendationId = "agw-3", name, id, tags, param1 = "webApplicationFirewallConfiguration: isNull"
| order by id asc



AGW-4 - Use Application GW V2 instead of V1

Category: System Efficiency

Impact: High

Guidance

You should use Application Gateway v2 unless there is a compelling reason for using v1. V2 has many more built in features such as autoscaling, static VIPs, Azure KeyVault integration for certificate management and many more features listed in our comparison charts. Leveraging this updated version allows for better performance and control of how your traffic routed and the ability to make changes to the traffic.

Resources

Resource Graph Query

// Azure Resource Graph Query
// Get all Application Gateways, which are using the deprecated V1 SKU
resources
| where type =~ 'microsoft.network/applicationgateways'
| extend tier = properties.sku.tier
| where tier == 'Standard' or tier == 'WAF'
| project recommendationId = "agw-4", name, id, tags



AGW-5 - Monitor and Log the configurations and traffic

Category: Monitoring

Impact: Medium

Guidance

Enable logs that can be stored in storage accounts, Log Analytics, and other monitoring services. If NSGs are applied NSG flow logs can be enabled and stored for traffic audit and to provide insights into the traffic flowing into your Azure Cloud.

Resources

Resource Graph Query

// cannot-be-validated-with-arg



AGW-6 - Use Health Probes to detect backend availability

Category: Monitoring

Impact: Medium

Guidance

Using custom health probes can help with understand the availability of your backends and allows you to monitor the backend services if they are being affected in any way.

Resources

Resource Graph Query

// Azure Resource Graph Query
// Application Gateways are not using health probes to monitor the availability of the backend systems
resources
| where type =~ "microsoft.network/applicationGateways"
| where array_length(properties.probes) == 0
| project recommendationId="agw-6", name, id, tags, param1="customHealthProbeUsed: false"



AGW-7 - Deploy Application Gateway in a zone-redundant configuration

Category: Availability

Impact: High

Guidance

Deploying your Application Gateway in a zone-aware configurations ensures that if a specific zone goes down that customers will still have access to the services as the other services located in other zones will still be available.

Resources

Resource Graph Query

// Azure Resource Graph Query
// list Application Gateways that are not configured to use at least 2 Availability Zones
resources
| where type =~ "microsoft.network/applicationGateways"
| where isnull(zones) or array_length(zones) < 2
| extend zoneValue = iff((isnull(zones)), "null", zones)
| project recommendationId = "agw-7", name, id, tags, param1="Zones: No Zone or Zonal", param2=strcat("Zones value: ", zoneValue )



AGW-8 - Plan for backend maintenance by using connection draining

Category: Governance

Impact: Medium

Guidance

Plan for backend maintenance by using connection draining. Connection draining helps you achieve graceful removal of backend pool members during planned service updates or problems with backend health. This setting is enabled via the Backend Setting and is applied to all backend pool members during rule creation.

Resources

Resource Graph Query

// Azure Resource Graph Query
// This query will check if connection draining is enabled
resources
| where type =~ "microsoft.network/applicationGateways"
| mv-expand backendHttpSettings = properties.backendHttpSettingsCollection
| extend connectionDrainingEnabled = backendHttpSettings.properties.connectionDraining.enabled
| where connectionDrainingEnabled != true
| extend backendPoolName = backendHttpSettings.name
| project recommendationId = "agw-8", name, id, tags, param1 = "connectionDraining: Disabled", param2 = strcat("backendSettingsName: ", backendPoolName)



AGW-9 - Ensure Application Gateway Subnet is using a /24 subnet mask

Category: Networking

Impact: High

Recommendation/Guidance

Application Gateway (Standard_v2 or WAF_v2 SKU) can support up to 125 instances. Although a /24 subnet isn’t required per Application Gateway v2 SKU deployment, it is highly recommended. This is to ensure that Application Gateway v2 has sufficient space for autoscaling expansion and maintenance upgrades.

Resources

Resource Graph Query

// Azure Resource Graph Query
// This query will validate the subnet id for an appGW ends with a /24

resources
| where type =~ 'Microsoft.Network/applicationGateways'
| extend subnetid = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id)
| join kind=leftouter(resources
    | where type == "microsoft.network/virtualnetworks"
    | mv-expand properties.subnets
    | extend subnetid = tostring(properties_subnets.id)
    | extend addressprefix = tostring(properties_subnets.properties.addressPrefix)
    | project subnetid, addressprefix) on subnetid
| where addressprefix !endswith '/24'
| project recommendationID = "agw-9", name, id, tags, param1 = strcat('AppGW subnet prefix: ', addressprefix)