Quick summary
Before going deeper, here is the simplest way to think about Azure Firewall Terraform.
azurerm_firewall, azurerm_firewall_policy, and often azurerm_firewall_policy_rule_collection_group. :contentReference[oaicite:2]{index=2}
Why use Terraform for Azure Firewall?
Azure Firewall can be deployed manually in the Azure portal, but Terraform is better when you need repeatable policy structure, reviewable rule logic, and reusable network security foundations.
- It keeps firewall and policy configuration in code instead of clicks.
- It makes rule changes visible in Git and code review.
- It reduces manual mistakes around subnets, public IPs, and rule ordering.
- It helps teams standardize centralized firewall patterns across environments.
- It fits naturally into CI/CD and reusable Azure network modules.
Terraform code
This example creates:
- an Azure resource group
- a virtual network
- the required AzureFirewallSubnet
- a public IP
- an Azure Firewall Policy
- an Azure Firewall instance
- a Firewall Policy Rule Collection Group with one network rule collection and one application rule collection
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_virtual_network" "vnet" {
name = var.vnet_name
address_space = ["10.70.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "firewall_subnet" {
name = "AzureFirewallSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.70.0.0/26"]
}
resource "azurerm_public_ip" "firewall_pip" {
name = var.public_ip_name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_firewall_policy" "fw_policy" {
name = var.firewall_policy_name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
dns {
proxy_enabled = true
servers = ["168.63.129.16"]
}
tags = {
environment = var.environment
managed_by = "terraform"
purpose = "centralized-firewall-policy"
}
}
resource "azurerm_firewall" "firewall" {
name = var.firewall_name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku_name = "AZFW_VNet"
sku_tier = "Standard"
firewall_policy_id = azurerm_firewall_policy.fw_policy.id
ip_configuration {
name = "firewall-ipconfig"
subnet_id = azurerm_subnet.firewall_subnet.id
public_ip_address_id = azurerm_public_ip.firewall_pip.id
}
tags = {
environment = var.environment
managed_by = "terraform"
purpose = "centralized-firewall"
}
}
resource "azurerm_firewall_policy_rule_collection_group" "fw_rcg" {
name = "default-rule-collection-group"
firewall_policy_id = azurerm_firewall_policy.fw_policy.id
priority = 100
network_rule_collection {
name = "network-rules"
priority = 100
action = "Allow"
rule {
name = "allow-ntp"
protocols = ["UDP"]
source_addresses = ["10.70.1.0/24"]
destination_addresses = ["13.86.101.172"]
destination_ports = ["123"]
}
}
application_rule_collection {
name = "application-rules"
priority = 200
action = "Allow"
rule {
name = "allow-microsoft"
source_addresses = ["10.70.1.0/24"]
destination_fqdns = [
"www.microsoft.com"
]
protocols {
port = 443
type = "Https"
}
}
}
}
Code breakdown
AzureFirewallSubnet
Azure Firewall requires a dedicated subnet named AzureFirewallSubnet, and Microsoft documents that this subnet must be at least a /26. This is one of the most important deployment requirements. :contentReference[oaicite:4]{index=4}
Public IP
The firewall needs a Standard public IP for many common deployment models. Azure also supports multi-public-IP patterns in separate examples. :contentReference[oaicite:5]{index=5}
Firewall Policy
Microsoft recommends Firewall Policy as the preferred configuration model for Azure Firewall, and the Terraform provider exposes azurerm_firewall_policy for this purpose. :contentReference[oaicite:6]{index=6}
Azure Firewall
The azurerm_firewall resource creates the firewall instance itself, attaches it to the required subnet, and links it to the Firewall Policy. :contentReference[oaicite:7]{index=7}
Rule Collection Group
Firewall Policy Rule Collection Groups organize network, application, and DNAT rule collections under the policy. Terraform exposes this through azurerm_firewall_policy_rule_collection_group. :contentReference[oaicite:8]{index=8}
Why this structure is useful
This example is practical because it follows the current Azure direction: firewall instance plus Firewall Policy plus rule collection groups, instead of treating the firewall itself as the whole configuration model. :contentReference[oaicite:9]{index=9}
Important firewall fields
A good Azure Firewall Terraform page should explain that deployment is not only about creating the firewall resource. Several fields strongly affect whether the design actually works.
| Field | What it controls | Example |
|---|---|---|
| sku_name | Firewall deployment mode for the resource | AZFW_VNet |
| sku_tier | Firewall SKU tier | Standard |
| firewall_policy_id | Which Firewall Policy the instance should use | policy resource ID |
| subnet_id | Which subnet hosts the firewall instance | AzureFirewallSubnet |
| public_ip_address_id | Which public IP is attached to the firewall IP configuration | Standard Public IP |
| proxy_enabled | Whether Firewall Policy DNS proxy is enabled | true |
Rule collection group model
In Azure’s current model, Firewall Policy is where the firewall logic lives, and Rule Collection Groups organize the actual rule collections beneath that policy. Microsoft’s Terraform quickstart uses this model with application and network rules, and the Terraform provider has a dedicated resource for it. :contentReference[oaicite:10]{index=10}
| Layer | Purpose | Simple explanation |
|---|---|---|
| Firewall Policy | Top-level policy object | The reusable policy container for Azure Firewall behavior |
| Rule Collection Group | Organizes collections under the policy | The ordered container that holds one or more rule collections |
| Rule Collection | Groups related rules | Such as one network rule collection or one application rule collection |
| Rule | The actual traffic match logic | For example allow NTP or allow HTTPS to a specific FQDN |
Suggested variables
Variables make Azure Firewall Terraform code more reusable across development, testing, and production environments.
variable "resource_group_name" {
description = "Name of the Azure resource group"
type = string
}
variable "location" {
description = "Azure region for deployment"
type = string
default = "South Africa North"
}
variable "vnet_name" {
description = "Name of the Azure Virtual Network"
type = string
}
variable "public_ip_name" {
description = "Name of the Azure Firewall public IP"
type = string
}
variable "firewall_name" {
description = "Name of the Azure Firewall instance"
type = string
}
variable "firewall_policy_name" {
description = "Name of the Azure Firewall Policy"
type = string
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
Example terraform.tfvars
resource_group_name = "rg-network-dev-san-1"
location = "South Africa North"
vnet_name = "vnet-hub-dev-san-1"
public_ip_name = "pip-fw-dev-san-1"
firewall_name = "fw-dev-san-1"
firewall_policy_name = "fwp-dev-san-1"
environment = "dev"
Suggested outputs
Outputs help expose firewall and policy IDs for validation or later modules.
output "firewall_id" {
value = azurerm_firewall.firewall.id
}
output "firewall_policy_id" {
value = azurerm_firewall_policy.fw_policy.id
}
output "firewall_public_ip" {
value = azurerm_public_ip.firewall_pip.ip_address
}
How to run it
A simple Terraform execution flow looks like this:
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply
In real teams, these steps often run through CI/CD after review rather than manually every time.
terraform fmt and terraform validate before planning or applying changes.
Real-world usage
This Azure Firewall Terraform pattern can grow into real enterprise security architecture workflows.
Hub-and-spoke centralized inspection
A platform team deploys one or more Azure Firewall instances in a hub VNet and uses route tables so spoke traffic passes through the firewall for outbound inspection.
Policy reuse across environments
A security team uses Firewall Policy to standardize application and network rule logic across multiple Azure environments or regions.
Outbound control plus NTP or update access
Teams use network rule collections for low-level traffic like NTP and application rule collections for outbound web access to approved destinations.
Best practices
- Use Firewall Policy for new designs.
- Keep AzureFirewallSubnet dedicated to the firewall only.
- Make sure the firewall subnet is at least /26 as documented by Azure.
- Use clear names for policies, rule collection groups, and public IPs.
- Be deliberate with route tables so traffic actually reaches the firewall.
- Plan DNS behavior early if using FQDN-based application rules or DNS proxy.
- Keep rule collections readable and logically grouped.
- Document why each rule collection exists, not only what it allows.
Common mistakes
- Using the wrong subnet name instead of AzureFirewallSubnet.
- Making the firewall subnet too small.
- Deploying the firewall correctly but forgetting route tables.
- Treating Firewall Policy as optional in new standardized designs.
- Mixing application-rule intent and network-rule intent without a clear structure.
- Assuming successful deployment means real traffic is being inspected.
Frequently asked questions
What Terraform resources are commonly used for Azure Firewall?
Common resources include azurerm_firewall, azurerm_firewall_policy, and azurerm_firewall_policy_rule_collection_group. :contentReference[oaicite:13]{index=13}
Why do Terraform Azure Firewall examples often include Firewall Policy?
Because Microsoft recommends Firewall Policy as the preferred configuration model for Azure Firewall. :contentReference[oaicite:14]{index=14}
What subnet name does Azure Firewall require?
Azure Firewall requires a dedicated subnet named AzureFirewallSubnet, and Microsoft documents that it must be at least a /26. :contentReference[oaicite:15]{index=15}
What should I learn after Azure Firewall Terraform?
A good next step is DNAT rule collections, route table steering, IP Groups, multi-public-IP designs, and broader hub-and-spoke inspection patterns. :contentReference[oaicite:16]{index=16}
Summary
Azure Firewall Terraform is one of the best practical ways to understand how centralized network inspection becomes infrastructure as code. It teaches you how firewall instances, Firewall Policy, and rule collection groups fit together and how reusable Azure security foundations are built in real environments.
Official Azure documentation
These official references are useful if you want deeper platform details for Azure Firewall, Firewall Policy, and Terraform deployment patterns.
- Create an Azure Firewall and a firewall policy - Terraform
- Terraform AzureRM firewall resource
- Terraform AzureRM firewall policy resource
- Terraform AzureRM firewall policy rule collection group resource
- Deploy Azure Firewall with Availability Zones - Terraform
- Create Azure Firewall and IP Groups - Terraform