Intro

When Azure firewall processes application rules, what happens? Does it SNAT? Does it Proxy? Does it do both? In this post we will find out.

Terraformo 🪄

I used my wizarding skills to build this lab. If you want to follow along, you can find the incantation here.

Warning
If you choose to spin up this lab, it costs real Muggle money to run (around $5 AUD/hour). Over the course of a week, I spent around $100 Australian Dollar Bucks testing and preparing this blog.

Architecture

The following high level architecture diagram is referenced in this post.

The following points describe the above diagram:

  • The network is deployed in a Hub and Spoke topology.
  • The Hub vNet contains an Azure firewall which is the default gateway for all spoke subnets.
  • Azure firewall has a single Public IP address assigned to facilitate communication to/from the internet.
  • Spoke vNets are peered with the hub via vNeT peering.
  • Spoke VMs are assinged RFC1918 Private IP addresses only.
  • Egress/Ingress traffic to/from the internet traverses the Azure firewall.
  • Spoke-to-Spoke traffic traverses the Azure firewall.
  • Private DNS Zones allow DNS resolution internal to Azure.
  • Key Vault stores the TLS inspection certificate.

IP Addressing

Prefixes

vNetSubnetPrefix
Hub vNetFirewall Subnet10.0.0.0/24
Spoke1 vNetClient Subnet192.168.0.0/24
Spoke2 vNetWorkload Subnet 1172.16.1.0/24
Spoke2 vNetWorkload Subnet 2172.16.2.0/24
Spoke2 vNetWorkload Subnet 3172.16.3.0/24

IP Addresses

HostIP AddressDescription
Azure Firewall10.0.0.x/24Random IP from Subnet Block
client192.168.0.4/24Client test VM.
webserver1172.16.1.4/24Internal - No TLS inspection
webserver2172.16.2.4/24Internal - TLS inspection
webserver3172.16.3.4/24Public - TLS inspection

Routing

The routing for this lab is depicted in the following diagram.

The following points describe the above diagram:

  • Traffic to/from the internet traverses the Azure firewall.
  • Outbound spoke traffic to the internet is Source NAT'd (SNAT) to 4.197.152.210
  • Inbound SSH traffic from $MY_PUBLIC_IP to 4.197.152.210 is Destination NAT'd (DNAT) to the appropriate host.
  • Inter-spoke vNet traffic transits via the hub vNet.
  • Azure firewall is the default gateway for all spoke subnets.
  • Intra-spoke vNet traffic stays within the spoke vNet.

DNS

To allow TLS inspection to work seemlessly without throwing scary warnings to clients we need to setup a few things, the first of which is DNS.

DNS Architecture

The following diagram shows the DNS architecture for this lab.

The components of the above design are explained in the following sections.

Domains

There are two domains used throughout this lab.

DomainDescription
stuffandthings.internalInternal only domain, not publicly registered
stratuslabs.netPublicly registered domain

Private DNS Zones

Private DNS zones are deployed to allow Azure resources to resolve domain names within Azure.

  • Both the stuffandthings.internal and stratuslabs.net Private Zones are deployed.
  • The private DNS zones are linked to the Hub vNet.
  • The Hub vNet is configured to use the Azure DNS resolver, this allows the records from the private DNS zones to be resolved by Azure firewall.

Public DNS Zone

The stratuslabs.net domain is registered publicly with Cloudflare.

  • We need a publicly registered domain to capture traffic from both sides of the TLS connection (More on this later).
  • No public A records are defined for the hosts in this lab.

Host Records

The following host records are added to the private DNS zones.

ZoneTypeNameIP Address
stuffandthings.internalAwebserver1172.16.1.4
stuffandthings.internalAwebserver2172.16.2.4
stratuslabs.netAwebserver3172.16.3.4

Domain Names

Virtual machines have the following domain names.

Virtual MachineFQDN
webserver1webserver1.stuffandthings.internal
webserver2webserver2.stuffandthings.internal
webserver3webserver3.stratuslabs.net

Proxy DNS

When utilising Azure firewall rules with FQDNs, it is recommended that the spoke resources use the same DNS server(s) as the Azure firewall to resolve hostnames.

The following configurations are enabed to meet this requirement.

  • Azure Firewall has Proxy DNS enabled. This allows the virtual machines to use the Azure Firewall as their DNS server.
  • Spoke vNets are configured to use the Azure firewall as the DNS server. The vNet DNS config is inherited by the spoke virtual machines when they boot up.
  • When DNS requests are received, they are forwarded to the Azure DNS resolver 168.63.129.16.
  • The Azure DNS resolver looks for records in Private DNS Zones attached to the hub vNet.
Warning
When filtering based on FQDNs, if spoke resources and Azure firewall do not use the same DNS resolvers, unpredictable behavour can occur. EG: Azure firewall may resolve a hostname to a different IP than a spoke resource. This can lead to traffic being processed incorrectly.

Certificates

To perform TLS inspection, x509 certificates need to be setup on both the client and servers with a mutual trusted Root Certificate Authority (CA). This lab uses both Self-Signed and Public CA certificates.

Chain of Trust

To establish a trust between a client and server, the server needs to present a certificate signed by a Root CA that the client also trusts.

In this lab we will setup a chain of trust as follows:

Certificate Chain
Root CA Certificate
|
+--> Intermediate CA Certificate
     |
     +--> Leaf (Server) Certificate

Some important points about the Certificate Chain:

  • Root CA - Signs Intermediate certificate and delegates the signer attribute. This allows the Intermediate CA to generate TLS certificates and man in the middle TLS connections.
  • Intermediate CA - When a request transits the firewall, a Leaf certificate for the destination is generated on the fly and signed by the Intermediate CA certificate.
  • The Root CA's public certificate must be installed on the client. Any server certificate signed by the intermediate CA will be trusted by the client as they share a common Root CA.

TLS Inspection Certificate Requirements

To perform TLS inspection, the Intermediate certificate must have the following configuration parameters:

  • Must be password-less and in the PKCS#12 format (with a certificate and a private key).
  • Must be a single certificate, and not include the full chain of certificates.
  • Must have an RSA private key >= 4096 bytes.
  • The CA flag, must be set to True.
  • Must have the KeyUsage extension marked as Critical with the KeyCertSign flag.
  • Must have the BasicConstraints extension marked as Critical.
  • Must be non-exportable, with the Path Length set to >=1.

Certificate Generation

Self-Signed Certificates

You can use the openssl CLI tool to create the necessecary certificates.

The following openssl.cnf file is used to define the correct configration parameters for the Root and Intermediate CA certificates.

openssl.cnf
[ req ]
default_bits        = 4096
distinguished_name  = req_distinguished_name
string_mask         = utf8only
default_md          = sha512

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address

[ rootCA_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ interCA_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:1
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ server_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature
extendedKeyUsage = serverAuth

Create the Root CA certificate.

cmd
# Create a Root CA private key and certificate.
openssl req -x509 -new -nodes \
    -newkey rsa:4096 -keyout rootCA.key \
    -sha256 -days 1024 -out rootCA.crt \
    -subj "/C=AU/ST=Queensland/O=StuffandThings/CN=StuffandThings Root CA" \
    -config openssl.cnf -extensions rootCA_ext"

Create the Intermediate CA certificate.

cmd
# Create intermediate CA private key and signing request.
openssl req -new -nodes -newkey rsa:4096 \
    -keyout interCA.key -sha256 -out interCA.csr \
    -subj "/C=AU/ST=Queensland/O=StuffandThings/CN=StuffandThings Intermediate CA"

# Sign on the intermediate CA request with the root CA producing an intermediate certificate.
openssl x509 -req -in interCA.csr \
    -CA rootCA.crt -CAkey rootCA.key \
    -CAcreateserial -out interCA.crt \
    -days 1024 -sha256 \
    -extfile openssl.cnf -extensions interCA_ext

# Export the intermediate CA into PFX format, excluding a password.
# The `interCA.pfx` file will be imported into Azure Key Vault.
openssl pkcs12 -export -out interCA.pfx \
    -inkey interCA.key -in interCA.crt \
    -password "pass:"

Create the certificates for websevers 1 and 2.

cmd
# Create webserver certificates.
for i in {1..2}
do
  # Generate a webserver private key.
  openssl genrsa -out webserver$i.key 2048

  # Create a certificate signing request.
  openssl req -new -key webserver$i.key -out webserver$i.csr \
    -subj "/C=AU/ST=Queensland/L=Brisbane/O=StuffandThings/CN=webserver$i.stuffandthings.internal" \
    -addext "subjectAltName=DNS:webserver$i.stuffandthings.internal"

  # Sign the webserver cert request with the intermediate CA producing a webserver certificate.
  openssl x509 -req -in webserver$i.csr -CA interCA.crt -CAkey interCA.key -CAcreateserial \
    -out webserver$i-alone.crt -days 365 -sha256 -extfile <(printf "subjectAltName=DNS:webserver$i.stuffandthings.internal")

  # Create a full-chain server certificate including the intermediate and root CA's.
  cat webserver$i-alone.crt interCA.crt rootCA.crt > webserver$i.crt
done
Public Certificate (Cloudflare)

I use Clouldflare for this lab as I host the stratuslabs.net domain there, and there's a Let's Encrypt plugin that makes requesting certificates a breeze. We need to generate an API Token to allow webserver3 to request a server certificate.

From your Cloudflare console, navigate to:

As a minimum, configure the following parameters.

Permissions
Token TypeServicePermisison
ZoneDNSEdit
Zone Resources
MembershipMatchDomain
IncludeSpecific Zonestratuslabs.net

Let's Encrypt Certificate

I won't cover the steps to request a certificate in detail, however, I can recommend this excellent blog post for additional details. The TL/DR is below.

On webserver3, switch to the root user and create a .secrets directory and cloudflare.ini file.

cmd
# Chanage to root user
sudo su -

# Create directory and file.
mkdir /root/.secrets && touch /root/.secrets/cloudflare.ini"

# Update permissions to super-duper-secret.
chmod 0700 /root/.secrets && sudo chmod 0400 /root/.secrets/cloudflare.ini

Add your Cloudflare API token to the cloudflare.ini file.

/root/.secrets/cloudflare.ini
dns_cloudflare_api_token="${CLOUDFLARE_API_TOKEN}"

Generate a Let's Encrypt wildcard certificate for webserver3.

cmd
sudo certbot certonly --agree-tos --no-eff-email -m ${EMAIL}@${DOMAIN} --dns-cloudflare --dns-cloudflare-credentials /root/.secrets/cloudflare.ini -d 'webserver3.stratuslabs.net'

The certificate and key will be created in the following locations.

ItemLocation
Certificate/etc/letsencrypt/live/webserver3.stratuslabs.net/fullchain.pem
Key/etc/letsencrypt/live/webserver3.stratuslabs.net/privkey.pem

Key Vault

Azure Key Vault can securely store Keys (Software and HSM), Certificates and Secrets. In this lab, we use key vault to store the previously created Intermediate CA certificate.

The following diagram outlines the Azure Key Vault deployment.

The above diagram can be described as follows:

  • The Intermediate Certificate: interCA.pfx is saved in Azure Key Vault in the PKCS#12 format.
  • The certificate has 2 parts: The public certificate, stored in Certificates, and the private key, stored in Secrets.
  • A Managed Identity is assigned to the firewall policy and used to access the certificate.

Managed Identitity

To access the certificate, Azure firewall needs access to the Key Vault. To allow this to happen, a User Assigned Managed Identity is configured with the following permissions:

  • Key Vault Certificate User
  • Key Vault Secrets User

The identity is then attached to the Azure firewall policy.

Firewall Policy

Most of the Azure firewall configuration, is done within a Firewall Policy object.

TLS Inspection

TLS inspection is enabled at the policy level. When enabled, you select the Key Vault where the Intermediate CA certificate is stored.

Note
To allow Azure firewall access the Key Vault, the previously discussed Managed Identity needs to be assigned to the Policy.

DNAT Rules

I have configured destination NAT to the virtual machines which allows me to SSH to them from my local network. No other DNAT is configured.

Source IP Destination IPDestination PortTranslated IPTranslated PortProtocol
$MY_PUBLIC_IP4.197.152.2102290172.16.0.422TCP
$MY_PUBLIC_IP4.197.152.2102291172.16.1.422TCP
$MY_PUBLIC_IP4.197.152.2102292172.16.2.422TCP
$MY_PUBLIC_IP4.197.152.2102293172.16.3.422TCP

Network Rules

Network rules only permit ICMP traffic from RFC1918 private addresses. This is to aid in connectivity troubleshooting within Azure.

SourceDestinationProtocolPortAction
RFC1918AnyICMPAnyAllow

Application Rules

For the application rules, HTTP/S is permitted to the hosts/domains we want to test.

The Any/Any rule exists mostly to allow the webservers to install the required packages via APT. For the purpose of this lab and to simplify the rules, I permitted all other HTTP/S (with TLS inspection disabled).

SourceDestinationProtocolPortActionTLS Inspection
192.168.0.0/24webserver1.stuffandthings.internalHTTP,HTTPS80,443Allow
192.168.0.0/24webserver2.stuffandthings.internalHTTP,HTTPS80,443Allow
192.168.0.0/24webserver3.stratuslabs.netHTTP,HTTPS80,443Allow
192.168.0.0/24google.comHTTP,HTTPS80,443Allow
192.168.0.0/24neverssl.comHTTP,HTTPS80,443Allow
192.168.0.0/24idontexist.intheetherHTTP,HTTPS80,443Allow
AnyAnyHTTP,HTTPS80,443Allow
Note
To actually perform the TLS inspection, it needs to be enabled on a per-rule basis.

Rule Processing Precedence

It's important to understand the order in which Azure firewalls process rules.

  1. Rules and collections are numbered 100-65500, with lower numbers having higer priority.
  2. Rule collection groups are processed in priority order.
  3. Rule collections are processed in priority order.
  4. DNAT rules.
  5. Network rules.
  6. Application rules.
Important
Firewall rules terminate processing on a match. Network rules are processed before Application rules. If a Network rule matches the traffic we want inspected by an Application rule, then the Application rule will never be processed.

Webserver Configuration

I am using Nginx as the webserver for this lab. I have enabled a very basic configuration to allow testing for both HTTP and HTTPS traffic.

Certificate and Private Key Location

Nginx will look for a Certificate and Private key in the following locations:

HostPrivate KeyPublic Certificate
webserver1/etc/nginx/ssl/webserver1.key/etc/nginx/ssl/webserver1.crt
webserver2/etc/nginx/ssl/webserver2.key/etc/nginx/ssl/webserver2.crt
webserver3/etc/letsencrypt/live/webserver3.stratuslabs.net/fullchain.pem/etc/letsencrypt/live/webserver3.stratuslabs.net/privkey.pem

Nginx Configuration

The configuration file is located at /etc/nginx/sites-available/default and is used for all 3 webservers.

/etc/nginx/sites-available/default
server {
    listen 80 default_server;
    server_name _;
    root /var/www/html;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

server {
    listen 443 ssl;
    ssl_certificate ${PUBLIC_CERTIFICATE_LOCATION}; # CHANGE_ME
    ssl_certificate_key ${PRIVATE_KEY_LOCATION}; # CHANGE_ME
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    root /var/www/html;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

Application Rule Considerations

Important information for Azure firewall application rule procesing:

  • Application rules are evaluated in the outbound direction only.
  • If required, Web Application Firewall (WAF) can be used to perform application filtering inbound.
  • TLS inspection is an application rule construct, therefore is performed in the outbound direction only. If inbound inspection is required, then an Application Gateway or Front Door is required.
  • Unlike Application Gateway, you cannot tell Azure Firewall to trust a certificate that is not issued by a well-known CA. This effectively means you can only perform TLS inspection on traffic destined for sites with certificates issued by a well-known CA.
  • For HTTP, rules are matched on the Host header.
  • For HTTPS, rules are matched on the Sever Name Indication (SNI) only.
  • In the cases of HTTP and TLS inspected HTTPS:
    • Azure firewall ignores the packet's destination IP address and uses the DNS resolved IP address from the Host header/SNI.
    • Azure firewall inserts an X-Forwarded-For header with the source clients IP Address.

Test Cases

The follow considerations are pertinent to test cases:

  • The tests goal is to determine how Azure firewall application rules process HTTP/S traffic.
  • Traffic is captured via tcpdump.
  • Where possible, traffic is captured on both sides of the firewall (Client and Server).
  • Client traffic is captured for every test case.
  • On the server side capture, traffic filters capture traffic from/to both the client and hub vNets.
  • The client IP address is 192.168.0.4 for all test cases.

The following table summarises the test case parameters.

ServerTLS InspectionClient CaptureServer Capture
http://webserver1.stuffandthings.internal:80
https://webserver1.stuffandthings.internal:443
http://webserver2.stuffandthings.internal:80
https://webserver2.stuffandthings.internal:443
http://webserver3.stratuslabs.net:80
https://webserver3.stratuslabs.net:443
http://google.com:80
https://google.com:443
http://neverssl.com:80
https://neverssl.com:443
http://idontexist.intheether:80
https://idontexist.intheether:443

Each test case has a record of the commands run to execute the test which include:

  • tcpdump commands to capture traffic on the client and server (where applicable).
  • curl command used to initiate traffic to the webservers.

The data caputured for the test cases can be found UPDATE_ME.

Client -> webserver1.stuffandthings.internal

HTTP
HostCommand
webserver1sudo tcpdump -i eth0 'tcp and port 80 and (net 10.0.0.0/24 or net 192.168.0.0/24)' -w webserver1-80.pcap
clientsudo tcpdump -i eth0 'tcp and port 80 and (net 10.0.0.0/24 or net 172.16.1.0/24)' -w client-webserver1-80.pcap
clientcurl -v http://webserver1.stuffandthings.internal/index.html > client-webserver1-80-curl.txt 2>&1
HTTPS
ParamValue
Client192.168.0.4
Serverwebserver1.stuffandthings.internal
ProtocolHTTPS
TLS Inspection
Status200 OK
Certificate IssuerStuffandThings Intermediate CA
Client Captureclient-webserver1-443.pcap
Server Capturewebserver1-443.pcap
Curl Logclient-webserver1-443-curl.txt
HostCommand
webserver1sudo tcpdump -i eth0 'tcp and port 443 and (net 10.0.0.0/24 or net 192.168.0.0/24)' -w webserver1-443.pcap
clientsudo tcpdump -i eth0 'tcp and port 443 and (net 10.0.0.0/24 or net 172.16.1.0/24)' -w client-webserver1-443.pcap
clientcurl -v https://webserver1.stuffandthings.internal/index.html > client-webserver1-443-curl.txt 2>&1

Client -> webserver2.stuffandthings.internal

HTTP
HostCommand
webserver2sudo tcpdump -i eth0 'tcp and port 80 and (net 10.0.0.0/24 or net 192.168.0.0/24)' -w webserver2-80.pcap
clientsudo tcpdump -i eth0 'tcp and port 80 and (net 10.0.0.0/24 or net 172.16.2.0/24)' -w client-webserver2-80.pcap
clientcurl -v http://webserver2.stuffandthings.internal/index.html > client-webserver2-80-curl.txt 2>&1
HTTPS
ParamValue
Client192.168.0.4
Serverwebserver2.stuffandthings.internal
ProtocolHTTPS
TLS Inspection
Status500 Internal Server Error
Certificate IssuerAzure Firewall Manager CA
Client Captureclient-webserver2-443.pcap
Server Capturewebserver2-443.pcap
Curl Logclient-webserver2-443-curl.txt
Error

Azure firewall does not recognize the Root CA that issued the server certificate, therefore the client receives an error: certificate signed by unknown authority. The error comes from Azure firewall.

HostCommand
webserver2sudo tcpdump -i eth0 'tcp and port 443 and (net 10.0.0.0/24 or net 192.168.0.0/24)' -w webserver2-443.pcap
clientsudo tcpdump -i eth0 'tcp and port 443 and (net 10.0.0.0/24 or net 172.16.2.0/24)' -w client-webserver2-443.pcap
clientcurl -v https://webserver2.stuffandthings.internal/index.html > client-webserver2-443-curl.txt 2>&1

Client -> webserver3.stratuslabs.net

HTTP
HostCommand
webserver3sudo tcpdump -i eth0 'tcp and port 80 and (net 10.0.0.0/24 or net 192.168.0.0/24)' -w webserver3-80.pcap
clientsudo tcpdump -i eth0 'tcp and port 80 and (net 10.0.0.0/24 or net 172.16.3.0/24)' -w client-webserver3-80.pcap
clientcurl -v http://webserver3.stratuslabs.net/index.html > client-webserver3-80-curl.txt 2>&1
HTTPS
ParamValue
Client192.168.0.4
Serverwebserver3.stuffandthings.internal
ProtocolHTTPS
TLS Inspection
Status200 OK
Certificate IssuerAzure Firewall Manager CA
Client Captureclient-webserver3-443.pcap
Server Capturewebserver3-443.pcap
Curl Logclient-webserver3-443-curl.txt
HostCommand
webserver3sudo tcpdump -i eth0 'tcp and port 443 and (net 10.0.0.0/24 or net 192.168.0.0/24)' -w webserver3-443.pcap
clientsudo tcpdump -i eth0 'tcp and port 443 and (net 10.0.0.0/24 or net 172.16.3.0/24)' -w client-webserver3-443.pcap
clientcurl -v https://webserver3.stratuslabs.net/index.html > client-webserver3-443-curl.txt 2>&1

Client -> google.com

HTTP
HostCommand
clientsudo tcpdump -i eth0 'tcp and port 80' -w client-google-80.pcap
clientcurl -v http://google.com > client-google-80-curl.txt 2>&1
HTTPS
HostCommand
clientsudo tcpdump -i eth0 'tcp and port 443' -w client-google-443.pcap
clientcurl -v https://google.com > client-google-443-curl.txt 2>&1

Client -> neverssl.com

HTTP
HostCommand
clientsudo tcpdump -i eth0 'tcp and port 80' -w client-neverssl-80.pcap
clientcurl -v http://neverssl.com > client-neverssl-80-curl.txt 2>&1
HTTPS
HostCommand
clientsudo tcpdump -i eth0 'tcp and port 443' -w client-neverssl-443.pcap
clientcurl -v https://neverssl.com > client-neverssl-443-curl.txt 2>&1

Client -> idontexist.intheether

A host entry was added to the client for the idontexist.intheether domain. This simulates what occurs when Azure Firewall cannot resolve a domain name.

HTTP
HostCommand
clientsudo tcpdump -i eth0 'tcp and port 80' -w client-idontexist-80.pcap
clientcurl -v http://idontexist.intheether > client-idontexist-80-curl.txt 2>&1
HTTPS
HostCommand
clientsudo tcpdump -i eth0 'tcp and port 443' -w client-idontexist-443.pcap
clientcurl -v https://idontexist.intheether > client-idontexist-443-curl.txt 2>&1

Test Results

Finally, let's determine what happens with NAT/Proxy when application rules are processed.

Plain-Text HTTP Traffic

TLS Inspected HTTPS

Non-TLS Inspected HTTPS

Non-TLS inspected HTTPS traffic is Source NAT'd (SNAT). Azure firewall cannot terminate the HTTPS connection, without triggering errors on the client. Therefore, SNAT at the network layer is the only option. The TCP and HTTP session is established between the Client and Server.

Unknown Domain Name

When Azure firewall cannot resolve the Domain Name the follow occurs.

  1. TCP request to Destination IP.
  2. AZFW receives TCP connection.
  3. AZFW responds to TCP connection.
  4. Client sends a HTTP request.
  5. AZFW looks up domain from Host Header/SNI and resolves destination hostname.
  6. AZFW, unable to resolve hostname sends HTTP/500 to client.
  7. Client receives HTTP response.

Summary

Theory

Azure firewall is doing more than SNAT, it's also acting like a Transparent Full Proxy. To quote some Azure documentation: "Application rules are always SNATed using a transparent proxy."[*]

It looks like AZFW buffers packets to inspect the HTTP Header/SNI to determine if it needs to process the packet via the application rules engine. If so, it responds to the source TCP session, spoofing the destination address, then initiates a new connection to the destination. This behaviour is evident when a Domain cannot be resolved by Azure firewall, the client gets a response from the Azure firewall, when the connection would normally timeout.

The test results are summarised in the table below:

ServerTLS InspectionSNATProxy
http://webserver1.stuffandthings.internal:80
https://webserver1.stuffandthings.internal:443
http://webserver2.stuffandthings.internal:80
https://webserver2.stuffandthings.internal:443
http://webserver3.stratuslabs.net:80
https://webserver3.stratuslabs.net:443
http://google.com:80
https://google.com:443
http://neverssl.com:80
https://neverssl.com:443
http://idontexist.intheether:80
https://idontexist.intheether:443

Outro

In this post, we took a deep dive into Azure Firewall Application Rule processing. It was a pretty long post and if you got this far, thanks for hanging in there.

✌️ Peace out nerds. Stay weird! ✌️

Tags