This module manages the creation and configuration of Azure Firewall resources in Microsoft Azure. It supports advanced features such as custom rule collections, policy association, threat intelligence settings, and IP configurations.
- Firewall Deployment: Provision Azure Firewall in a specified virtual network and subnet (
AzureFirewallSubnet
). - IP Configuration: Support for both public and private IP configurations.
- Firewall Policies: Attach Azure Firewall Policies to centralize rule and configuration management.
- Rule Collections: Define network, application, and NAT rule collections directly within the module.
- Threat Intelligence: Enable threat intelligence-based filtering to detect and block traffic from known malicious IP addresses.
This example demonstrates how to deploy an Azure Firewall with custom rule collections and optional policy association.
resource "azurerm_resource_group" "rg" {
name = "rg-nic-example"
location = "germanywestcentral"
}
module "vnet" {
source = "CloudAstro/virtual-network/azurerm"
name = "vnet-example"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
module "snet" {
source = "CloudAstro/subnet/azurerm"
name = "AzureFirewallSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = module.vnet.virtual_network.name
address_prefixes = ["10.0.1.0/24"]
}
module "management_snet" {
source = "CloudAstro/subnet/azurerm"
name = "AzureFirewallManagementSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = module.vnet.virtual_network.name
address_prefixes = ["10.0.2.0/24"]
}
module "public_ip_fw" {
source = "CloudAstro/public-ip/azurerm"
name = "public-ip-fw"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
allocation_method = "Static"
zones = ["1", "2", "3"]
}
module "public_ip_mgmt" {
source = "CloudAstro/public-ip/azurerm"
name = "public-ip-mgmt"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
allocation_method = "Static"
zones = ["1", "2", "3"]
}
module "firewall" {
source = "../.."
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
name = "fw-hub"
sku_name = "AZFW_VNet"
sku_tier = "Standard"
zones = ["1", "2", "3"]
firewall_policy_id = null
dns_servers = ["168.63.129.16", "8.8.8.8"]
dns_proxy_enabled = true
private_ip_ranges = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
threat_intel_mode = "Alert"
ip_configuration = {
ipconfig = {
name = "fw-ipconfig"
subnet_id = module.snet.subnet.id
public_ip_address_id = module.public_ip_fw.publicip.id
}
}
management_ip_configuration = {
name = "fw-mgmt"
subnet_id = module.management_snet.subnet.id
public_ip_address_id = module.public_ip_mgmt.publicip.id
}
application_rule_collection = {
app_rules = {
name = "fw-app-rules"
resource_group_name = azurerm_resource_group.rg.name
priority = 100
action = "Allow"
rules = [
{
name = "rule1"
description = "Allow example traffic"
source_addresses = ["10.0.0.0/24"]
target_fqdns = ["example.com"]
protocols = [{
type = "Http"
port = 80
},
{
type = "Https"
port = 443
}]
}
]
}
}
nat_rule_collection = {
nat_rules = {
name = "fw-nat-rules"
resource_group_name = azurerm_resource_group.rg.name
priority = 100
action = "Dnat"
rules = [
{
name = "nat-rule1"
description = "NAT rule example"
source_addresses = ["0.0.0.0/0"]
destination_addresses = [module.public_ip_fw.publicip.ip_address]
destination_ports = ["80"]
protocols = ["TCP"]
translated_address = "10.0.1.10"
translated_port = 8080
}
]
}
}
tags = {
environment = "production"
team = "network"
}
}
Name | Version |
---|---|
terraform | ~> 1.9.0 |
azurerm | >= 4.0.0 |
Name | Version |
---|---|
azurerm | >= 4.0.0 |
Name | Type |
---|---|
azurerm_firewall.this | resource |
azurerm_firewall_application_rule_collection.app_rule_collection | resource |
azurerm_firewall_nat_rule_collection.nat_rule_collection | resource |
azurerm_management_lock.this | resource |
azurerm_monitor_diagnostic_setting.this | resource |
azurerm_role_assignment.this | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
location | * location - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created.Example Input: location = "germanywestcentral" |
string |
n/a | yes |
name | * name - (Required) Specifies the name of the Firewall. Changing this forces a new resource to be created. Example Input: name = "fw-gwc-dev" |
string |
n/a | yes |
resource_group_name | * resource_group_name - (Required) The name of the resource group in which to create the resource. Changing this forces a new resource to be created. Example Input: resource_group_name = "rg-azure-firewall-dev" |
string |
n/a | yes |
sku_name | * sku_name - (Required) SKU name of the Firewall. Possible values are AZFW_Hub and AZFW_VNet . Changing this forces a new resource to be created.Example Input: sku_name = "AZFW_Hub" |
string |
n/a | yes |
sku_tier | * sku_tier - (Required) SKU tier of the Firewall. Possible values are Premium , Standard and Basic .Example Input: sku_tier = "Standard" |
string |
n/a | yes |
application_rule_collection | * firewall_application_rule_collection - Manages an Application Rule Collection within an Azure Firewall.* name - (Required) Specifies the name of the Application Rule Collection which must be unique within the Firewall. Changing this forces a new resource to be created.* azure_firewall_name - (Required) Specifies the name of the Firewall in which the Application Rule Collection should be created. Changing this forces a new resource to be created.* resource_group_name - (Required) Specifies the name of the Resource Group in which the Firewall exists. Changing this forces a new resource to be created.* priority - (Required) Specifies the priority of the rule collection. Possible values are between 100 - 65000 .* action - (Required) Specifies the action the rule will apply to matching traffic. Possible values are Allow and Deny .* rule - (Required) One or more rule blocks as defined below.* name - (Required) Specifies the name of the rule.* description - (Optional) Specifies a description for the rule.* source_addresses - (Optional) A list of source IP addresses and/or IP ranges.* source_ip_groups - (Optional) A list of source IP Group IDs for the rule.-> NOTE At least one of source_addresses and source_ip_groups must be specified for a rule.* fqdn_tags - (Optional) A list of FQDN tags. Possible values are AppServiceEnvironment , AzureBackup , AzureKubernetesService , HDInsight , MicrosoftActiveProtectionService , WindowsDiagnostics , WindowsUpdate and WindowsVirtualDesktop .* target_fqdns - (Optional) A list of FQDNs.* protocol - (Optional) One or more protocol blocks as defined below.* port - (Required) Specify a port for the connection.* type - (Required) Specifies the type of connection. Possible values are Http , Https and Mssql .Example Input: application_rule_collection = { |
map(object({ |
null |
no |
diagnostic_settings | The following arguments are supported: * name - (Required) Specifies the name of the Diagnostic Setting. Changing this forces a new resource to be created.-> NOTE: If the name is set to 'service' it will not be possible to fully delete the diagnostic setting. This is due to legacy API support. * target_resource_id - (Required) The ID of an existing Resource on which to configure Diagnostic Settings. Changing this forces a new resource to be created.* eventhub_name - (Optional) Specifies the name of the Event Hub where Diagnostics Data should be sent.-> NOTE: If this isn't specified then the default Event Hub will be used. * eventhub_authorization_rule_id - (Optional) Specifies the ID of an Event Hub Namespace Authorization Rule used to send Diagnostics Data.-> NOTE: This can be sourced from the azurerm_eventhub_namespace_authorization_rule resource and is different from a azurerm_eventhub_authorization_rule resource.-> NOTE: At least one of eventhub_authorization_rule_id , log_analytics_workspace_id , partner_solution_id and storage_account_id must be specified.* enabled_log - (Optional) One or more enabled_log blocks as defined below.-> NOTE: At least one enabled_log or metric block must be specified. At least one type of Log or Metric must be enabled.* category - (Optional) The name of a Diagnostic Log Category for this Resource.-> NOTE: The Log Categories available vary depending on the Resource being used. You may wish to use the azurerm_monitor_diagnostic_categories Data Source or list of service specific schemas to identify which categories are available for a given Resource.* category_group - (Optional) The name of a Diagnostic Log Category Group for this Resource.-> NOTE: Not all resources have category groups available. -> NOTE: Exactly one of category or category_group must be specified.* log_analytics_workspace_id - (Optional) Specifies the ID of a Log Analytics Workspace where Diagnostics Data should be sent.-> NOTE: At least one of eventhub_authorization_rule_id , log_analytics_workspace_id , partner_solution_id and storage_account_id must be specified.* enabled_metric - (Optional) One or more enabled_metric blocks as defined below.-> Note: At least one enabled_log or enabled_metric block must be specified.* category - (Required) The name of a Diagnostic Metric Category for this Resource.-> Note: The Metric Categories available vary depending on the Resource being used. You may wish to use the azurerm_monitor_diagnostic_categories Data Source to identify which categories are available for a given Resource.* storage_account_id - (Optional) The ID of the Storage Account where logs should be sent.-> NOTE: At least one of eventhub_authorization_rule_id , log_analytics_workspace_id , partner_solution_id and storage_account_id must be specified.* log_analytics_destination_type - (Optional) Possible values are AzureDiagnostics and Dedicated . When set to Dedicated , logs sent to a Log Analytics workspace will go into resource specific tables, instead of the legacy AzureDiagnostics table.-> NOTE: This setting will only have an effect if a log_analytics_workspace_id is provided. For some target resource type (e.g., Key Vault), this field is unconfigurable. Please see resource types for services that use each method. Please see the documentation for details on the differences between destination types.* partner_solution_id - (Optional) The ID of the market partner solution where Diagnostics Data should be sent. For potential partner integrations, click to learn more about partner integration.-> NOTE: At least one of eventhub_authorization_rule_id , log_analytics_workspace_id , partner_solution_id and storage_account_id must be specified.* timeouts - The timeouts block allows you to specify timeouts for certain actions:* create - (Defaults to 30 minutes) Used when creating the Diagnostics Setting.* read - (Defaults to 5 minutes) Used when retrieving the Diagnostics Setting.* update - (Defaults to 30 minutes) Used when updating the Diagnostics Setting.* delete - (Defaults to 1 hour) Used when deleting the Diagnostics Setting.Example Input: diagnostic_settings = { |
map(object({ |
{} |
no |
dns_proxy_enabled | * dns_proxy_enabled - (Optional) Whether DNS proxy is enabled. It will forward DNS requests to the DNS servers when set to true . It will be set to true if dns_servers provided with a not empty list.Example Input: dns_proxy_enabled = true |
bool |
null |
no |
dns_servers | * dns_servers - (Optional) A list of DNS servers that the Azure Firewall will direct DNS traffic to the for name resolution.Example Input: dns_servers = ["8.8.8.8", "8.8.4.4"] |
list(string) |
null |
no |
firewall_policy_id | * firewall_policy_id - (Optional) The ID of the Firewall Policy applied to this Firewall.Example Input: firewall_policy_id = "/subscriptions/12345678-9abc-def0-1234-56789abcdef0/resourceGroups/rg-firewall/providers/Microsoft.Network/firewallPolicies/fw-policy-default" |
string |
null |
no |
ip_configuration | * ip_configuration - (Optional) An ip_configuration block as documented below.* name - (Required) Specifies the name of the IP Configuration.* subnet_id - (Optional) Reference to the subnet associated with the IP Configuration. Changing this forces a new resource to be created.-> NOTE The Subnet used for the Firewall must have the name AzureFirewallSubnet and the subnet mask must be at least a /26 .-> NOTE At least one and only one ip_configuration block may contain a subnet_id .* public_ip_address_id - (Optional) The ID of the Public IP Address associated with the firewall.-> NOTE A public ip address is required unless a management_ip_configuration block is specified.-> NOTE When multiple ip_configuration blocks with public_ip_address_id are configured, terraform apply will raise an error when one or some of these ip_configuration blocks are removed. because the public_ip_address_id is still used by the firewall resource until the firewall resource is updated. and the destruction of azurerm_public_ip happens before the update of firewall by default. to destroy of azurerm_public_ip will cause the error. The workaround is to set create_before_destroy=true to the azurerm_public_ip resource lifecycle block. See more detail: destroying.md#create-before-destroy-> NOTE The Public IP must have a Static allocation and Standard SKU.Example Input: ip_configuration = { |
map(object({ |
{} |
no |
lock | * managment_lock - Manages a Management Lock which is scoped to a Subscription, Resource Group or Resource.* name - (Required) Specifies the name of the Management Lock. Changing this forces a new resource to be created.* scope - (Required) Specifies the scope at which the Management Lock should be created. Changing this forces a new resource to be created.* lock_level - (Required) Specifies the Level to be used for this Lock. Possible values are CanNotDelete and ReadOnly . Changing this forces a new resource to be created.~> Note: CanNotDelete means authorized users are able to read and modify the resources, but not delete. ReadOnly means authorized users can only read from a resource, but they can't modify or delete it.* notes - (Optional) Specifies some notes about the lock. Maximum of 512 characters. Changing this forces a new resource to be created.Example Input: lock = { |
object({ |
null |
no |
management_ip_configuration | * management_ip_configuration - (Optional) A management_ip_configuration block as documented below, which allows force-tunnelling of traffic to be performed by the firewall. Adding or removing this block or changing the subnet_id in an existing block forces a new resource to be created. Changing this forces a new resource to be created.* name - (Required) Specifies the name of the IP Configuration.* subnet_id - (Required) Reference to the subnet associated with the IP Configuration. Changing this forces a new resource to be created.-> NOTE The Management Subnet used for the Firewall must have the name AzureFirewallManagementSubnet and the subnet mask must be at least a /26 .* public_ip_address_id - (Required) The ID of the Public IP Address associated with the firewall.-> NOTE The Public IP must have a Static allocation and Standard SKU.Example Input: management_ip_configuration = { |
object({ |
null |
no |
nat_rule_collection | * firewall_nat_rule_collection - Manages a NAT Rule Collection within an Azure Firewall.* name - (Required) Specifies the name of the NAT Rule Collection which must be unique within the Firewall. Changing this forces a new resource to be created.* azure_firewall_name - (Required) Specifies the name of the Firewall in which the NAT Rule Collection should be created. Changing this forces a new resource to be created.* resource_group_name - (Required) Specifies the name of the Resource Group in which the Firewall exists. Changing this forces a new resource to be created.* priority - (Required) Specifies the priority of the rule collection. Possible values are between 100 - 65000 .* action - (Required) Specifies the action the rule will apply to matching traffic. Possible values are Dnat and Snat .* rule - (Required) One or more rule blocks as defined below.* name - (Required) Specifies the name of the rule.* description - (Optional) Specifies a description for the rule.* destination_addresses - (Required) A list of destination IP addresses and/or IP ranges.* destination_ports - (Required) A list of destination ports.* protocols - (Required) A list of protocols. Possible values are Any , ICMP , TCP and UDP . If action is Dnat , protocols can only be TCP and UDP .* source_addresses - (Optional) A list of source IP addresses and/or IP ranges.* source_ip_groups - (Optional) A list of source IP Group IDs for the rule.-> NOTE At least one of source_addresses and source_ip_groups must be specified for a rule.* translated_address - (Required) The address of the service behind the Firewall.* translated_port - (Required) The port of the service behind the Firewall.Example Input: nat_rule_collection = { |
map(object({ |
null |
no |
private_ip_ranges | * private_ip_ranges - (Optional) A list of SNAT private CIDR IP ranges, or the special string IANAPrivateRanges, which indicates Azure Firewall does not SNAT when the destination IP address is a private range per IANA RFC 1918.Example Input: private_ip_ranges = ["10.20.0.0/24", "192.168.0.0/16"] |
list(string) |
null |
no |
role_assignments | * role_assignments - Assigns a given Principal (User or Group) to a given Role.* name - (Optional) A unique UUID/GUID for this Role Assignment - one will be generated if not specified. Changing this forces a new resource to be created.* scope - (Required) The scope at which the Role Assignment applies to, such as /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333 , /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333/resourceGroups/myGroup , or /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333/resourceGroups/myGroup/providers/Microsoft.Compute/virtualMachines/myVM , or /providers/Microsoft.Management/managementGroups/myMG . Changing this forces a new resource to be created.* role_definition_id - (Optional) The Scoped-ID of the Role Definition. Changing this forces a new resource to be created. Conflicts with role_definition_name .* role_definition_name - (Optional) The name of a built-in Role. Changing this forces a new resource to be created. Conflicts with role_definition_id .* principal_id - (Required) The ID of the Principal (User, Group or Service Principal) to assign the Role Definition to. Changing this forces a new resource to be created.* ~> NOTE: The Principal ID is also known as the Object ID (ie not the "Application ID" for applications). * principal_type - (Optional) The type of the principal_id . Possible values are User , Group and ServicePrincipal . Changing this forces a new resource to be created. It is necessary to explicitly set this attribute when creating role assignments if the principal creating the assignment is constrained by ABAC rules that filters on the PrincipalType attribute.* ~> NOTE: If one of condition or condition_version is set both fields must be present.* condition - (Optional) The condition that limits the resources that the role can be assigned to. Changing this forces a new resource to be created.* condition_version - (Optional) The version of the condition. Possible values are 1.0 or 2.0 . Changing this forces a new resource to be created.* delegated_managed_identity_resource_id - (Optional) The delegated Azure Resource Id which contains a Managed Identity. Changing this forces a new resource to be created.* ~> NOTE: this field is only used in cross tenant scenario. * description - (Optional) The description for this Role Assignment. Changing this forces a new resource to be created.* skip_service_principal_aad_check - (Optional) If the principal_id is a newly provisioned Service Principal set this value to true to skip the Azure Active Directory check which may fail due to replication lag. This argument is only valid if the principal_id is a Service Principal identity. Defaults to false .* ~> NOTE: If it is not a Service Principal identity it will cause the role assignment to fail.* timeouts - The timeouts block allows you to specify timeouts for certain actions:* create - (Defaults to 30 minutes) Used when creating the Role Assignment.* read - (Defaults to 5 minutes) Used when retrieving the Role Assignment.* delete - (Defaults to 30 minutes) Used when deleting the Role Assignment.Example Input: role_assignments = { |
map(object({ |
{} |
no |
tags | * tags - (Optional) A mapping of tags to assign to the resource.Example Input: tags = { |
map(string) |
null |
no |
threat_intel_mode | * threat_intel_mode - (Optional) The operation mode for threat intelligence-based filtering. Possible values are: Off , Alert and Deny . Defaults to Alert .Example Input: threat_intel_mode = "Alert" |
string |
"Alert" |
no |
timeouts | * timeouts - The timeouts block allows you to specify timeouts for certain actions:* create - (Defaults to 90 minutes) Used when creating the Firewall.* read - (Defaults to 5 minutes) Used when retrieving the Firewall.* update - (Defaults to 90 minutes) Used when updating the Firewall.* delete - (Defaults to 90 minutes) Used when deleting the Firewall.Example Input: timeouts = { |
object({ |
null |
no |
virtual_hub | * virtual_hub - (Optional) A virtual_hub block as documented below.* virtual_hub_id - (Required) Specifies the ID of the Virtual Hub where the Firewall resides in.* public_ip_count - (Optional) Specifies the number of public IPs to assign to the Firewall. Defaults to 1 .Example Input: virtual_hub = { |
object({ |
null |
no |
zones | * zones - (Optional) Specifies a list of Availability Zones in which this Azure Firewall should be located. Changing this forces a new Azure Firewall to be created.-> Please Note: Availability Zones are only supported in several regions at this time. Example Input: zones = ["1", "2", "3"] |
list(string) |
null |
no |
Name | Description |
---|---|
firewall | * name - (Required) Specifies the name of the Firewall. Changing this forces a new resource to be created.* resource_group_name - (Required) The name of the resource group in which to create the resource. Changing this forces a new resource to be created.* location - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created.* sku_name - (Required) SKU name of the Firewall. Possible values are AZFW_Hub and AZFW_VNet . Changing this forces a new resource to be created.* sku_tier - (Required) SKU tier of the Firewall. Possible values are Premium , Standard and Basic .* firewall_policy_id - (Optional) The ID of the Firewall Policy applied to this Firewall.* dns_servers - (Optional) A list of DNS servers that the Azure Firewall will direct DNS traffic to the for name resolution.* dns_proxy_enabled - (Optional) Whether DNS proxy is enabled. It will forward DNS requests to the DNS servers when set to true . It will be set to true if dns_servers provided with a not empty list.* private_ip_ranges - (Optional) A list of SNAT private CIDR IP ranges, or the special string IANAPrivateRanges , which indicates Azure Firewall does not SNAT when the destination IP address is a private range per IANA RFC 1918.* threat_intel_mode - (Optional) The operation mode for threat intelligence-based filtering. Possible values are: Off , Alert and Deny . Defaults to Alert .* zones - (Optional) Specifies a list of Availability Zones in which this Azure Firewall should be located. Changing this forces a new Azure Firewall to be created.* tags - (Optional) A mapping of tags to assign to the resource.An ip_configuration block supports the following:* name - (Required) Specifies the name of the IP Configuration.* subnet_id - (Optional) Reference to the subnet associated with the IP Configuration. Changing this forces a new resource to be created.* public_ip_address_id - (Optional) The ID of the Public IP Address associated with the firewall.A management_ip_configuration block supports the following:* name - (Required) Specifies the name of the IP Configuration.* subnet_id - (Required) Reference to the subnet associated with the IP Configuration. Changing this forces a new resource to be created.* public_ip_address_id - (Required) The ID of the Public IP Address associated with the firewall.A virtual_hub block supports the following:* virtual_hub_id - (Required) Specifies the ID of the Virtual Hub where the Firewall resides in.* public_ip_count - (Optional) Specifies the number of public IPs to assign to the Firewall. Defaults to 1 .Example output: output "name" { |
No modules.
For more information about Azure Firewall and configurations, refer to the Azure Firewall documentation. This module is designed to manage an Azure Firewall, including configurations for RBAC, network access, and rule assignments.
- Prioritize rules with high traffic to enhance performance.
- Select the appropriate SKU (Standard or Premium) for your workload.
- Monitor firewall throughput and adjust configurations as needed.
- Deploy Azure Firewall across multiple availability zones for higher resilience.
- Implement least privilege access by configuring minimal, necessary traffic rules.
- Organize rule collections efficiently to reduce evaluation time.
- Activate threat intelligence-based filtering for advanced protection.
- Validate your Terraform configuration to ensure that Azure Firewall is created and configured correctly, including diagnostic settings and role assignments.
This module is licensed under the MIT License. See the LICENSE file for more details.