So over the last year or so I’ve had a lot of fun extending client environments to Azure. One of the methods I’ve used has been leveraging Azure Application Gateway (AAG) with Web Application Firewall (WAF) to protect these services.

The AAG’s with WAF have been a very fast and cost effective way for clients to deploy fast and protected services to Azure without the requirement for expensive 3rd-party WAF appliance licenses. Some clients are even using these without any backend services living in Azure but take advantage of Azures scale to present and protect their on-premises services.

There are a lot of docs out there on what AAG’s are and what features the WAF brings to the plate, so I won’t go into a sales pitch here.

There are also some good how-to’s on the basics of getting an AAG up and how to configure them. Some here:
https://docs.microsoft.com/en-us/azure/application-gateway/quick-create-powershell
https://docs.microsoft.com/en-us/azure/application-gateway/tutorial-ssl-powershell

What I will do though, is share one of my dirty top down PS scripts that I use to deploy demo AAG’s for clients to see how they work. Most of the code is directly sourced from the links above, not claiming it as my own, just putting it all together and adding a twist of Daniel to it  🙂

It is assumed that you have the appropriate access to deploy the resources

Pre-built resources:

  • Resource Group
  • Virtual Network
  • Subnet is the first in the network
  • Backend VM deployed and working (in my case this was for an ADFS extension)
  • Appropriate SSL exported as PFX ($sslpath) and as Base64 ($cerpath)

*note you can adjust the script to suit your needs

What does the script do?

  1. Defines some variables
  2. Looks for existing PIP and if not then creates one
  3. Gets the backend IP of the VM defined
  4. Define AAG Backend Pool with a custom Probe
  5. Define AAG Listener
  6. Define AAG Rule
  7. Define AAG Type and Size
  8. Deploys the AAG

 

Ok, now as with all my code, it’s use at your own risk and comes with no warranties.. But, this does work assuming you use it correctly.

Before we get into it, to help understand how an AAG with WAF works, I borrowed this image from Joroen Nielsen (@jeroennieson) which helps visualise the workflow.

 

 

 

 

 

 

 

Anyway, hope this helps someone get up and running faster with AAG and WAF using PowerShell..

 

$prefix = "DA-"
$RGName = "<insert RG name here>"

$AAGName = "$($prefix)AAG"
$URL = "adfs.yourdomain.com"
$Loc = "AustraliaSouthEast"
$probepath = "/adfs/ls/IdpInitiatedSignon.aspx" # this demo is for ADFS, set your probe accordingly

#
#
$PIPName = "$($AAGName)-PIP"
$VMName = "<your WAP vm  name here>" #Name of existing VM
$VNetName = "<insert your vnet name here>" #name of existing VNet

#
#SSL cert with private key
$sslpath = "C:\temp\ssl.pfx" # update with your pfx4 cert location
$sslpwd = 'MySSLisSecure1234' # your pfx password
#export as Base64
$cerpath = "C:\temp\ssl64.cer" # update with your base6 cert location


#
# Only modify below here if you want to define custom names and settings
#

#Public IP Address
$pip = Get-AzureRmPublicIPAddress -ResourceGroupName $RGName -Name $PIPName -ErrorAction SilentlyContinue
if(-Not $pip){
    $pip = New-AzureRmPublicIpAddress `
        -Name $PIPName `
        -AllocationMethod Dynamic `
        -IpAddressVersion IPv4 `
        -Sku Basic -ResourceGroupName $RGName `
        -Location $Loc
}

# Virtual Network and Subnet details
$vnet = Get-AzureRmVirtualNetwork -ResourceGroupName $RGName -Name $VNetName
$subnet=$vnet.Subnets[0]
$gipconfig = New-AzureRmApplicationGatewayIPConfiguration `
  -Name "$($AAGName)-IP-Internal" `
  -Subnet $subnet
$fipconfig = New-AzureRmApplicationGatewayFrontendIPConfig `
  -Name "$($AAGName)-IP-Frontend" `
  -PublicIPAddress $pip
$frontendport = New-AzureRmApplicationGatewayFrontendPort `
  -Name "$($AAGName)-Port-443" `
  -Port 443

#Get Backend VM network interface
$BackendVM = Get-AzureRmVM -Name $VMName -ResourceGroupName $RGName
$NIC = Get-AzureRmNetworkInterface -ResourceGroupName $RGName | Where-Object {$_.Id -eq $BackendVM.NetworkProfile.NetworkInterfaces[0].Id}
Get-AzureRmNetworkInterfaceIpConfig -NetworkInterface $NIC

# Define AAG Backend Pool
$backendPool = New-AzureRmApplicationGatewayBackendAddressPool `
  -Name "$($AAGName)-BackendPool" `
  -BackendIPAddresses $NIC.ipconfigurations[0].privateipaddress

#Define Custom probe
$probe = New-AzureRmApplicationGatewayProbeConfig `
    -Name "$($AAGName)-HTTPS-Probe" `
    -Path $probepath `
    -HostName $URL `
    -Interval 30 `
    -Protocol Https `
    -Timeout 30 `
    -UnhealthyThreshold 3

$authcert = New-AzureRmApplicationGatewayAuthenticationCertificate `
    -Name "$($AAGName)-CER" `
    -CertificateFile $cerpath 

$poolSettings = New-AzureRmApplicationGatewayBackendHttpSettings `
  -Name "$($AAGName)-BackendSetting" `
  -Port 443 `
  -Protocol Https `
  -CookieBasedAffinity Disabled `
  -RequestTimeout 120 `
  -AuthenticationCertificates $authcert `
  -Probe $probe 

$pwd = ConvertTo-SecureString -String $sslpwd -Force -AsPlainText
$cert = New-AzureRmApplicationGatewaySslCertificate `
  -Name "$($AAGName)CER" `
  -CertificateFile $sslpath `
  -Password $pwd

# Define AAG Listener
$defaultlistener = New-AzureRmApplicationGatewayHttpListener `
  -Name "$($AAGName)-Listener" `
  -Protocol Https `
  -HostName $URL `
  -FrontendIPConfiguration $fipconfig `
  -FrontendPort $frontendport `
  -SslCertificate $cert

# Define AAG Rule
$frontendRule = New-AzureRmApplicationGatewayRequestRoutingRule `
  -Name "$($AAGName)-Rule" `
  -RuleType Basic `
  -HttpListener $defaultlistener `
  -BackendAddressPool $backendPool `
  -BackendHttpSettings $poolSettings

# Define AAG Type and Size
$sku = New-AzureRmApplicationGatewaySku `
  -Name WAF_Medium `
  -Tier WAF `
  -Capacity 2

$wafconfig = New-AzureRmApplicationGatewayWebApplicationFirewallConfiguration `
    -Enabled $true `
    -FirewallMode Detection `
    -RuleSetType OWASP `
    -RuleSetVersion 3.0

# Deploy AAG
New-AzureRmApplicationGateway `
  -Name $AAGName `
  -ResourceGroupName $RGName `
  -Location $Loc `
  -BackendAddressPools $backendPool `
  -BackendHttpSettingsCollection $poolSettings `
  -FrontendIpConfigurations $fipconfig `
  -GatewayIpConfigurations $gipconfig `
  -FrontendPorts $frontendport `
  -HttpListeners $defaultlistener `
  -RequestRoutingRules $frontendRule `
  -Sku $sku `
  -SslCertificates $cert `
  -AuthenticationCertificates $authcert `
  -WebApplicationFirewallConfiguration $wafconfig `
  -Probes $probe

 

So, after you run the script, it will take about 30mins or so to deploy and configure the AAG. Below is the working AAG after deploying using the script. 

Showing the AAG Public  IP

image

Showing the https web application, in this case it’s the ADFS login.

image

And finally showing the TCP connection pointing at the AAG Public IP – no trickery here 😉

image

Anyway, hope this helpful to someone…

Enjoy!
Dan

Leave A Comment