Quickstart: Create an Azure Firewall and a firewall policy - Terraform
In this quickstart, you use Terraform to create an Azure Firewall and a firewall policy. The firewall policy has an application rule that allows connections to www.microsoft.com
and a rule that allows connections to Windows Update using the WindowsUpdate FQDN tag. A network rule allows UDP connections to a time server at 13.86.101.172.
Also, IP Groups are used in the rules to define the Source IP addresses.
Hashicorp Terraform is an open-source IaC (Infrastructure-as-Code) tool for provisioning and managing cloud infrastructure. It codifies infrastructure in configuration files that describe the desired state for your topology. Terraform enables the management of any infrastructure - such as public clouds, private clouds, and SaaS services - by using Terraform providers.
For information about Azure Firewall Manager, see What is Azure Firewall Manager?.
For information about Azure Firewall, see What is Azure Firewall?.
For information about IP Groups, see IP Groups in Azure Firewall.
- An Azure account with an active subscription. Create an account for free.
- Azure subscription: If you don't have an Azure subscription, create a free account before you begin.
Note
The sample code for this article is located in the Azure Terraform GitHub repo. You can view the log file containing the test results from current and previous versions of Terraform.
See more articles and sample code showing how to use Terraform to manage Azure resources
Multiple Azure resources are defined in the Terraform code. The following resources are defined in the main.tf
file:
- azurerm_resource_group
- azurerm_virtual_network
- azurerm_subnet
- azurerm_ip_group
- azurerm_public_ip
- azurerm_firewall_policy
- azurerm_firewall_policy_rule_collection_group
- azurerm_firewall
Create a directory in which to test the sample Terraform code and make it the current directory.
Create a file named
provider.tf
and insert the following code:terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~>3.0" } random = { source = "hashicorp/random" version = "~>3.0" } } } provider "azurerm" { features {} }
Create a file named
main.tf
and insert the following code:resource "random_pet" "rg-name" { prefix = var.resource_group_name_prefix } resource "azurerm_resource_group" "rg" { name = random_pet.rg-name.id location = var.resource_group_location } resource "azurerm_virtual_network" "azfw_vnet" { name = "azfw-vnet" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name address_space = ["10.10.0.0/24"] } resource "azurerm_ip_group" "workload_ip_group" { name = "workload-ip-group" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location cidrs = ["10.20.0.0/24", "10.30.0.0/24"] } resource "azurerm_ip_group" "infra_ip_group" { name = "infra-ip-group" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location cidrs = ["10.40.0.0/24", "10.50.0.0/24"] } resource "azurerm_subnet" "azfw_subnet" { name = "AzureFirewallSubnet" resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.azfw_vnet.name address_prefixes = ["10.10.0.0/26"] } resource "azurerm_public_ip" "pip_azfw" { name = "pip-azfw" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name allocation_method = "Static" sku = "Standard" } resource "azurerm_firewall_policy" "azfw_policy" { name = "azfw-policy" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location sku = var.firewall_sku_tier threat_intelligence_mode = "Alert" } resource "azurerm_firewall_policy_rule_collection_group" "net_policy_rule_collection_group" { name = "DefaultNetworkRuleCollectionGroup" firewall_policy_id = azurerm_firewall_policy.azfw_policy.id priority = 200 network_rule_collection { name = "DefaultNetworkRuleCollection" action = "Allow" priority = 200 rule { name = "time-windows" protocols = ["UDP"] source_ip_groups = [azurerm_ip_group.workload_ip_group.id, azurerm_ip_group.infra_ip_group.id] destination_ports = ["123"] destination_addresses = ["132.86.101.172"] } } } resource "azurerm_firewall_policy_rule_collection_group" "app_policy_rule_collection_group" { name = "DefaulApplicationtRuleCollectionGroup" firewall_policy_id = azurerm_firewall_policy.azfw_policy.id priority = 300 application_rule_collection { name = "DefaultApplicationRuleCollection" action = "Allow" priority = 500 rule { name = "AllowWindowsUpdate" description = "Allow Windows Update" protocols { type = "Http" port = 80 } protocols { type = "Https" port = 443 } source_ip_groups = [azurerm_ip_group.workload_ip_group.id, azurerm_ip_group.infra_ip_group.id] destination_fqdn_tags = ["WindowsUpdate"] } rule { name = "Global Rule" description = "Allow access to Microsoft.com" protocols { type = "Https" port = 443 } destination_fqdns = ["*.microsoft.com"] terminate_tls = false source_ip_groups = [azurerm_ip_group.workload_ip_group.id, azurerm_ip_group.infra_ip_group.id] } } } resource "azurerm_firewall" "fw" { name = "azfw" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name sku_name = "AZFW_VNet" sku_tier = var.firewall_sku_tier ip_configuration { name = "azfw-ipconfig" subnet_id = azurerm_subnet.azfw_subnet.id public_ip_address_id = azurerm_public_ip.pip_azfw.id } firewall_policy_id = azurerm_firewall_policy.azfw_policy.id }
Create a file named
variables.tf
and insert the following code:variable "resource_group_location" { type = string description = "Location for all resources." default = "eastus" } variable "resource_group_name_prefix" { type = string description = "Prefix for the Resource Group Name that's combined with a random id so name is unique in your Azure subcription." default = "rg" } variable "firewall_sku_tier" { type = string description = "Firewall SKU." default = "Premium" # Valid values are Standard and Premium validation { condition = contains(["Standard", "Premium"], var.firewall_sku_tier) error_message = "The sku must be one of the following: Standard, Premium" } }
Create a file named
outputs.tf
and insert the following code, being sure to update the value to your own backend hostname:output "resource_group_name" { value = azurerm_resource_group.rg.name } output "firewall_name" { value = azurerm_firewall.fw.name }
Run terraform init to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources.
terraform init -upgrade
Key points:
- The
-upgrade
parameter upgrades the necessary provider plugins to the newest version that complies with the configuration's version constraints.
Run terraform plan to create an execution plan.
terraform plan -out main.tfplan
Key points:
- The
terraform plan
command creates an execution plan, but doesn't execute it. Instead, it determines what actions are necessary to create the configuration specified in your configuration files. This pattern allows you to verify whether the execution plan matches your expectations before making any changes to actual resources. - The optional
-out
parameter allows you to specify an output file for the plan. Using the-out
parameter ensures that the plan you reviewed is exactly what is applied.
Run terraform apply to apply the execution plan to your cloud infrastructure.
terraform apply main.tfplan
Key points:
- The example
terraform apply
command assumes you previously ranterraform plan -out main.tfplan
. - If you specified a different filename for the
-out
parameter, use that same filename in the call toterraform apply
. - If you didn't use the
-out
parameter, callterraform apply
without any parameters.
When you no longer need the resources created via Terraform, do the following steps:
Run terraform plan and specify the
destroy
flag.terraform plan -destroy -out main.destroy.tfplan
Key points:
- The
terraform plan
command creates an execution plan, but doesn't execute it. Instead, it determines what actions are necessary to create the configuration specified in your configuration files. This pattern allows you to verify whether the execution plan matches your expectations before making any changes to actual resources. - The optional
-out
parameter allows you to specify an output file for the plan. Using the-out
parameter ensures that the plan you reviewed is exactly what is applied.
- The
Run terraform apply to apply the execution plan.
terraform apply main.destroy.tfplan