This module manages an Azure Firewall with key security features like RBAC, threat intelligence, app and NAT rules, and network access settings.
- Application and Network Rules: Allows filtering of traffic by fully qualified domain names (FQDNs) for HTTP/S and other protocols, as well as by IP addresses, ports, and protocols.
- Threat Intelligence: Alerts and denies traffic from/to known malicious IP addresses and domains.
- DNS Proxy and Custom DNS: Processes and forwards DNS queries from virtual networks to your desired DNS server, and allows configuration of custom DNS settings.
- Web Categories: Allows administrators to filter outbound user access to the internet based on categories (e.g., social networking, search engines, gambling).
- **URL Filtering: Allows administrators to filter outbound access to specific URLs, not just FQDNs.
- Intrusion Detection and Prevention System (IDPS): Monitors network activities for malicious activity, logs information about this activity, reports it, and optionally attempts to block it.
- Transport Layer Security (TLS) Inspection: Decrypts outbound traffic, processes the data, then encrypts the data and sends it to the destination.
This example provisions an Azure Firewall with Azure Policy with essential security settings for application rules, NAT rules, and threat intelligence.
resource "azurerm_resource_group" "rg" {
name = "rg-afwp-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"]
}
resource "azurerm_user_assigned_identity" "this" {
location = azurerm_resource_group.rg.location
name = "user-managed-identity"
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_ip_group" "source_ip_group" {
name = "ipg-source-health-check"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
}
resource "azurerm_ip_group" "destination_ip_group" {
name = "ipg-destination-app"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
}
module "public_ip" {
source = "CloudAstro/public-ip/azurerm"
name = "public-ip-fwp"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
allocation_method = "Static"
zones = ["1", "2", "3"]
}
module "firewall" {
source = "CloudAstro/firewall/azurerm"
name = "firewall-example"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku_name = "AZFW_VNet"
sku_tier = "Premium"
firewall_policy_id = module.firewall_policy.firewall_policy.id
ip_configuration = {
ip1 = {
name = "configuration1"
subnet_id = module.snet.subnet.id
public_ip_address_id = module.public_ip.publicip.id
}
}
}
module "firewall_policy" {
source = "../.."
location = azurerm_resource_group.rg.location
name = "my-firewall-policy"
resource_group_name = azurerm_resource_group.rg.name
base_policy_id = null
private_ip_ranges = ["10.0.0.0/8", "192.168.1.0/24", "100.64.0.0/10"]
auto_learn_private_ranges_enabled = true
sku = "Premium"
threat_intelligence_mode = "Alert"
sql_redirect_allowed = false
tags = {
environment = "dev"
owner = "team-network"
}
dns = {
proxy_enabled = false
servers = ["8.8.8.8", "1.1.1.1"]
}
identity = {
type = "UserAssigned"
identity_ids = [azurerm_user_assigned_identity.this.id]
}
intrusion_detection = {
mode = "Alert"
private_ranges = ["10.0.0.0/8"]
signature_overrides = [
{
id = "200001"
state = "Deny"
}
]
traffic_bypass = [
{
name = "bypass-example"
protocol = "TCP"
description = "Allow bypass for health checks"
destination_ip_groups = [azurerm_ip_group.destination_ip_group.id]
destination_ports = ["80", "443"]
source_ip_groups = [azurerm_ip_group.source_ip_group.id]
}
]
}
threat_intelligence_allowlist = {
fqdns = ["example.com"]
ip_addresses = ["10.0.0.0/16", "192.168.1.25", ]
}
explicit_proxy = {
enabled = true
http_port = 3128
https_port = 3129
enable_pac_file = false
pac_file_port = 8080
}
rule_collection_group = {
rule1 = {
name = "example-rule-collection-group"
priority = 100
application_rule_collections = {
application-access = {
name = "application-access"
action = "Allow"
priority = 100
rules = [
{
name = "allow-full-feature-access"
description = "Demonstrates usage of all supported fields in application rule"
source_ip_groups = [azurerm_ip_group.source_ip_group.id]
destination_urls = ["dev.azure.com", "login.microsoftonline.com"]
destination_fqdn_tags = ["AzureActiveDirectory", "WindowsUpdate"]
terminate_tls = true
web_categories = ["Finance", "SocialNetworking"]
protocols = [
{
type = "Http"
port = 80
},
{
type = "Https"
port = 443
}
]
http_headers = [
{
name = "X-Environment"
value = "Production"
},
{
name = "X-Custom-Header"
value = "FirewallPolicyDemo"
}
]
}
]
}
}
nat_rule_collections = {
nat-rule-collection-1 = {
name = "nat-rule-collection"
priority = 300
action = "Dnat"
rules = [
{
name = "dnat-ssh"
description = "NAT rule using translated IP address"
protocols = ["TCP", "UDP"]
source_ip_groups = [azurerm_ip_group.source_ip_group.id]
destination_address = module.public_ip.publicip.ip_address
destination_ports = ["3389"]
translated_address = "10.0.1.4"
translated_port = "3389"
},
{
name = "nat-rule-fqdn-translation"
description = "NAT rule using translated FQDN"
protocols = ["TCP"]
source_ip_groups = [azurerm_ip_group.source_ip_group.id]
destination_address = module.public_ip.publicip.ip_address
destination_ports = ["443"]
translated_fqdn = "internal-app.contoso.com"
translated_port = "443"
}
]
}
}
network_rule_collections = {
network-collection-1 = {
name = "network-rule-collection"
priority = 200
action = "Allow"
rules = [
{
name = "network-rule-complete-1"
description = "Allow TCP and UDP traffic to specific IPs and ports"
protocols = ["TCP", "UDP"]
source_ip_groups = [azurerm_ip_group.source_ip_group.id]
destination_ports = ["443", "80", "22"]
destination_ip_groups = [azurerm_ip_group.destination_ip_group.id]
},
{
name = "network-rule-complete-2"
description = "Allow ICMP traffic with minimal source"
protocols = ["ICMP"]
source_addresses = ["172.16.0.0/16"]
destination_ports = ["*"]
destination_addresses = ["*"]
},
{
name = "network-rule-complete-3"
description = "Allow all protocols using service tags"
protocols = ["Any"]
source_ip_groups = [azurerm_ip_group.source_ip_group.id]
destination_ports = ["1433"]
destination_addresses = ["Sql.EastUS"]
}
]
}
}
}
}
}
Name | Version |
---|---|
terraform | ~> 1.9.0 |
azurerm | >= 4.0.0 |
Name | Version |
---|---|
azurerm | >= 4.0.0 |
Name | Type |
---|---|
azurerm_firewall_policy.firewall_policy | resource |
azurerm_firewall_policy_rule_collection_group.rule_collection_group | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
location | * location - (Required) The Azure Region where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created.Example Input: location = "germanywestcentral" |
string |
n/a | yes |
name | * name - (Required) The name which should be used for this Firewall Policy. Changing this forces a new Firewall Policy to be created.Example Input: name = "azure-firewall-policy" |
string |
n/a | yes |
resource_group_name | * resource_group_name - (Required) The name of the Resource Group where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created.Example Input: resource_group_name = "rg-azure-firewall" |
string |
n/a | yes |
auto_learn_private_ranges_enabled | * auto_learn_private_ranges_enabled - (Optional) Whether enable auto learn private ip range.Example Input: auto_learn_private_ranges_enabled = false |
bool |
false |
no |
base_policy_id | * base_policy_id - (Optional) The ID of the base Firewall Policy.Example Input: base_policy_id = "/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.Network/firewallPolicies/<base_policy_name>" |
string |
null |
no |
dns | * dns - (Optional) A dns block as defined below.* proxy_enabled - (Optional) Whether to enable DNS proxy on Firewalls attached to this Firewall Policy? Defaults to false .* servers - (Optional) A list of custom DNS servers' IP addresses.Example Input: dns = { |
object({ |
null |
no |
explicit_proxy | * explicit_proxy - (Optional) A explicit_proxy block as defined below.* enabled - (Optional) Whether the explicit proxy is enabled for this Firewall Policy.* http_port - (Optional) The port number for explicit http protocol.* https_port - (Optional) The port number for explicit proxy https protocol.* enable_pac_file - (Optional) Whether the pac file port and url need to be provided.* pac_file_port - (Optional) Specifies a port number for firewall to serve PAC file.* pac_file - (Optional) Specifies a SAS URL for PAC file.Example Input: explicit_proxy = { |
object({ |
null |
no |
identity | * identity - (Optional) An identity block as defined below:* type - (Required) Specifies the type of Managed Service Identity that should be configured on this Firewall Policy. Only possible value is UserAssigned .* identity_ids - (Optional) Specifies a list of User Assigned Managed Identity IDs to be assigned to this Firewall Policy.Example Input: identity = { |
object({ |
null |
no |
insights | * insights - (Optional) An insights block as defined below.* enabled - (Required) Whether the insights functionality is enabled for this Firewall Policy.* default_log_analytics_workspace_id - (Required) The ID of the default Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to, when there is no location matches in the log_analytics_workspace .* retention_in_days - (Optional) The log retention period in days.* log_analytics_workspace - (Optional) A list of log_analytics_workspace block as defined below.* id - (Required) The ID of the Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to when their locations match the firewall_location .* firewall_location - (Required) The location of the Firewalls, that when matches this Log Analytics Workspace will be used to consume their logs.Example Input: insights = { |
object({ |
null |
no |
intrusion_detection | * intrusion_detection - (Optional) A intrusion_detection block as defined below.* mode - (Optional) In which mode you want to run intrusion detection: Off , Alert or Deny .* signature_overrides - (Optional) One or more signature_overrides blocks as defined below.* id - (Optional) 12-digit number (id) which identifies your signature.* state - (Optional) state can be any of Off , Alert or Deny .* traffic_bypass - (Optional) One or more traffic_bypass blocks as defined below.* name - (Required) The name which should be used for this bypass traffic setting.* protocol - (Required) The protocols any of ANY , TCP , ICMP , UDP that shall be bypassed by intrusion detection.* description - (Optional) The description for this bypass traffic setting.* destination_addresses - (Optional) Specifies a list of destination IP addresses that shall be bypassed by intrusion detection.* destination_ip_groups - (Optional) Specifies a list of destination IP groups that shall be bypassed by intrusion detection.* destination_ports - (Optional) Specifies a list of destination IP ports that shall be bypassed by intrusion detection.* source_addresses - (Optional) Specifies a list of source addresses that shall be bypassed by intrusion detection.* source_ip_groups - (Optional) Specifies a list of source IP groups that shall be bypassed by intrusion detection.* private_ranges - (Optional) A list of Private IP address ranges to identify traffic direction. By default, only ranges defined by IANA RFC 1918 are considered private IP addresses.Example Input: intrusion_detection = { |
object({ |
null |
no |
private_ip_ranges | * private_ip_ranges - (Optional) A list of private IP ranges to which traffic will not be SNAT.Example Input: private_ip_ranges = ["10.0.0.0/24", "192.168.1.0/24"] |
list(string) |
null |
no |
rule_collection_group | * rule_collection_group - (Optional) Manages a Firewall Policy Rule Collection Group.* name - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.* firewall_policy_id - (Required) The ID of the Firewall Policy where the Firewall Policy Rule Collection Group should exist. Changing this forces a new Firewall Policy Rule Collection Group to be created.* priority - (Required) The priority of the Firewall Policy Rule Collection Group. The range is 100-65000.* application_rule_collection - (Optional) One or more application_rule_collection blocks as defined below.* name - (Required) The name which should be used for this application rule collection.* action - (Required) The action to take for the application rules in this collection. Possible values are Allow and Deny .* priority - (Required) The priority of the application rule collection. The range is 100 - 65000 .* rule - (Required) One or more application_rule blocks as defined below.* name - (Required) The name which should be used for this rule.* description - (Optional) The description which should be used for this rule.* source_addresses - (Optional) Specifies a list of source IP addresses (including CIDR, IP range and * ).* source_ip_groups - (Optional) Specifies a list of source IP groups.* destination_addresses - (Optional) Specifies a list of destination IP addresses (including CIDR, IP range and * ).* destination_urls - (Optional) Specifies a list of destination URLs for which policy should hold. Needs Premium SKU for Firewall Policy. Conflicts with destination_fqdns .* destination_fqdns - (Optional) Specifies a list of destination FQDNs. Conflicts with destination_urls .* destination_fqdn_tags - (Optional) Specifies a list of destination FQDN tags.* terminate_tls - (Optional) Boolean specifying if TLS shall be terminated (true) or not (false). Must be true when using destination_urls . Needs Premium SKU for Firewall Policy.* web_categories - (Optional) Specifies a list of web categories to which access is denied or allowed depending on the value of action above. Needs Premium SKU for Firewall Policy.* protocols - (Optional) One or more protocols blocks as defined below.* type - (Required) Protocol type. Possible values are Http and Https .* port - (Required) Port number of the protocol. Range is 0-64000.* http_headers - (Optional) Specifies a list of HTTP/HTTPS headers to insert. One or more http_headers blocks as defined below.* name - (Required) Specifies the name of the header.* value - (Required) Specifies the value of the value.* nat_rule_collection - (Optional) One or more nat_rule_collection blocks as defined below.* name - (Required) The name which should be used for this NAT rule collection.* action - (Required) The action to take for the NAT rules in this collection. Currently, the only possible value is Dnat .* priority - (Required) The priority of the NAT rule collection. The range is 100 - 65000 .* rule - (Required) A nat_rule block as defined below.* name - (Required) The name which should be used for this rule.* description - (Optional) The description which should be used for this rule.* protocols - (Required) Specifies a list of network protocols this rule applies to. Possible values are TCP , UDP .* source_addresses - (Optional) Specifies a list of source IP addresses (including CIDR, IP range and * ).* source_ip_groups - (Optional) Specifies a list of source IP groups.* destination_address - (Optional) The destination IP address (including CIDR).* destination_ports - (Optional) Specifies a list of destination ports. Only one destination port is supported in a NAT rule.* translated_address - (Optional) Specifies the translated address.* translated_fqdn - (Optional) Specifies the translated FQDN.~> NOTE: Exactly one of translated_address and translated_fqdn should be set.* translated_port - (Required) Specifies the translated port.* network_rule_collection - (Optional) One or more network_rule_collection blocks as defined below.* name - (Required) The name which should be used for this network rule collection.* action - (Required) The action to take for the network rules in this collection. Possible values are Allow and Deny .* priority - (Required) The priority of the network rule collection. The range is 100 - 65000 .* rule - (Required) One or more network_rule blocks as defined below.* name - (Required) The name which should be used for this rule.* description - (Optional) The description which should be used for this rule.* protocols - (Required) Specifies a list of network protocols this rule applies to. Possible values are Any , TCP , UDP , ICMP .* destination_ports - (Required) Specifies a list of destination ports.* source_addresses - (Optional) Specifies a list of source IP addresses (including CIDR, IP range and * ).* source_ip_groups - (Optional) Specifies a list of source IP groups.* destination_addresses - (Optional) Specifies a list of destination IP addresses (including CIDR, IP range and * ) or Service Tags.* destination_ip_groups - (Optional) Specifies a list of destination IP groups.* destination_fqdns - (Optional) Specifies a list of destination FQDNs.Example Input: rule_collection_group = { |
map(object({ |
null |
no |
sku | * sku - (Optional) The SKU Tier of the Firewall Policy. Possible values are Standard , Premium and Basic . Defaults to Standard . Changing this forces a new Firewall Policy to be created.Example Input: sku = "Standard" |
string |
"Standard" |
no |
sql_redirect_allowed | * sql_redirect_allowed - (Optional) Whether SQL Redirect traffic filtering is allowed. Enabling this flag requires no rule using ports between 11000 -11999 .Example Input: sql_redirect_allowed = false |
bool |
false |
no |
tags | * tags - (Optional) A mapping of tags to assign to the resource.Example Input: tags = { |
map(string) |
null |
no |
threat_intelligence_allowlist | * threat_intelligence_allowlist - (Optional) A threat_intelligence_allowlist block as defined below.* fqdns - (Optional) A list of FQDNs that will be skipped for threat detection.* ip_addresses - (Optional) A list of IP addresses or CIDR ranges that will be skipped for threat detection.Example Input: threat_intelligence_allowlist = { |
object({ |
null |
no |
threat_intelligence_mode | * threat_intelligence_mode - (Optional) The operation mode for Threat Intelligence. Possible values are Alert , Deny and Off . Defaults to Alert .Example Input: threat_intelligence_mode = "Alert" |
string |
"Alert" |
no |
tls_certificate | * tls_certificate - (Optional) A tls_certificate block as defined below.* key_vault_secret_id - (Required) The ID of the Key Vault, where the secret or certificate is stored.* name - (Required) The name of the certificate.Example Input: tls_certificate = { |
object({ |
null |
no |
Name | Description |
---|---|
firewall_policy | * location - (Required) The Azure Region where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created.* name - (Required) The name which should be used for this Firewall Policy. Changing this forces a new Firewall Policy to be created.* resource_group_name - (Required) The name of the Resource Group where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created.* base_policy_id - (Optional) The ID of the base Firewall Policy.* dns - (Optional) A dns block as defined below.* proxy_enabled - (Optional) Whether to enable DNS proxy on Firewalls attached to this Firewall Policy? Defaults to false .* servers - (Optional) A list of custom DNS servers' IP addresses.* identity - (Optional) An identity block as defined below.* type - (Required) Specifies the type of Managed Service Identity that should be configured on this Firewall Policy. Only possible value is UserAssigned .* identity_ids - (Optional) Specifies a list of User Assigned Managed Identity IDs to be assigned to this Firewall Policy.* insights - (Optional) An insights block as defined below.* enabled - (Required) Whether the insights functionality is enabled for this Firewall Policy.* default_log_analytics_workspace_id - (Required) The ID of the default Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to, when there is no location matches in the log_analytics_workspace .* retention_in_days - (Optional) The log retention period in days.* log_analytics_workspace - (Optional) A list of log_analytics_workspace block as defined below.* id - (Required) The ID of the Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to when their locations match the firewall_location .* firewall_location - (Required) The location of the Firewalls, that when matches this Log Analytics Workspace will be used to consume their logs.* intrusion_detection - (Optional) A intrusion_detection block as defined below.* mode - (Optional) In which mode you want to run intrusion detection: Off , Alert or Deny .* signature_overrides - (Optional) One or more signature_overrides blocks as defined below.* id - (Optional) 12-digit number (id) which identifies your signature.* state - (Optional) state can be any of Off , Alert or Deny .* traffic_bypass - (Optional) One or more traffic_bypass blocks as defined below.* name - (Required) The name which should be used for this bypass traffic setting.* protocol - (Required) The protocols any of ANY , TCP , ICMP , UDP that shall be bypassed by intrusion detection.* description - (Optional) The description for this bypass traffic setting.* destination_addresses - (Optional) Specifies a list of destination IP addresses that shall be bypassed by intrusion detection.* destination_ip_groups - (Optional) Specifies a list of destination IP groups that shall be bypassed by intrusion detection.* destination_ports - (Optional) Specifies a list of destination IP ports that shall be bypassed by intrusion detection.* source_addresses - (Optional) Specifies a list of source addresses that shall be bypassed by intrusion detection.* source_ip_groups - (Optional) Specifies a list of source IP groups that shall be bypassed by intrusion detection.* private_ranges - (Optional) A list of Private IP address ranges to identify traffic direction. By default, only ranges defined by IANA RFC 1918 are considered private IP addresses.* private_ip_ranges - (Optional) A list of private IP ranges to which traffic will not be SNAT.* auto_learn_private_ranges_enabled - (Optional) Whether enable auto learn private ip range.* sku - (Optional) The SKU Tier of the Firewall Policy. Possible values are Standard , Premium and Basic . Defaults to Standard . Changing this forces a new Firewall Policy to be created.* tags - (Optional) A mapping of tags which should be assigned to the Firewall Policy.* threat_intelligence_allowlist - (Optional) A threat_intelligence_allowlist block as defined below.* fqdns - (Optional) A list of FQDNs that will be skipped for threat detection.* ip_addresses - (Optional) A list of IP addresses or CIDR ranges that will be skipped for threat detection.* threat_intelligence_mode - (Optional) The operation mode for Threat Intelligence. Possible values are Alert , Deny and Off . Defaults to Alert .* tls_certificate - (Optional) A tls_certificate block as defined below.* key_vault_secret_id - (Required) The Secret Identifier (URI) of the certificate stored in Azure Key Vault, either as a secret or certificate.* name - (Required) The name of the certificate.* sql_redirect_allowed - (Optional) Whether SQL Redirect traffic filtering is allowed. Enabling this flag requires no rule using ports between 11000 -11999 .* explicit_proxy - (Optional) A explicit_proxy block as defined below.* enabled - (Optional) Whether the explicit proxy is enabled for this Firewall Policy.* http_port - (Optional) The port number for explicit http protocol.* https_port - (Optional) The port number for explicit proxy https protocol.* enable_pac_file - (Optional) Whether the pac file port and url need to be provided.* pac_file_port - (Optional) Specifies a port number for firewall to serve PAC file.* pac_file - (Optional) Specifies a SAS URL for PAC file.Example Input: output "name" { |
No modules.
For more information about Azure Firewall Policies and configurations, refer to the Azure Firewall Policies documentation. This module is designed to manage an Azure Firewall Policies, including Application and Network Rules.
- Group rules logically into collections (e.g., separate application and network rules). Use descriptive names for easy identification.
- Use parent and child policies wisely. Ensure the parent policy contains common baseline rules, and child policies only override or extend where necessary.
- Ensure there are no conflicting rules in the same or different policies, as this can lead to unexpected behavior.
- Always test new policies or updates in a non-production environment before applying them to live firewalls.
- Activate threat intelligence-based filtering to block or alert on traffic from known malicious sources.
- Avoid overly granular rules that may increase complexity and management overhead
- Validate your Terraform configuration to ensure that Azure Firewall Policy is created and configured correctly.
This module is licensed under the MIT License. See the LICENSE file for more details.