Terraform - Deploy Azure Firewall into Virtual Network
Hello everyone! Azure offers a variety of security solutions, and Azure Firewall is a particularly effective tool. It is a fully managed cloud-native network firewall that provides top-notch protection for our virtual network resources.
In this blog post, you will learn how to use Terraform to deploy Azure Firewall in an already existing Azure network. By implementing Infrastructure as Code (IaC), the deployment process can be simplified, minimizing the risk of human errors and making your deployments more effective.
Prerequisites #
- You need Terraform CLI on your local machine, if you’re new to using Terraform to deploy Microsoft Azure resources, then I recommend you check out this link.
- A text editor or IDE of your choice (Visual Studio Code with Terraform extension is my recommendation)
Declare Azure Provider in Terraform #
The provider.tf file in Terraform is used to specify and configure the providers used in your Terraform configuration. A provider is a service or platform where the resources will be managed. This could be a cloud provider like Microsoft Azure, AWS, Google Cloud, etc.
This file is important because it tells Terraform which provider’s API to use when creating, updating, and deleting resources. Without it, Terraform wouldn’t know where to manage your resources.
provider "azurerm" {
features {}
}
Create an Azure Firewall using Terraform #
In the case of Azure Firewall deployment, the main.tf file contains the following key components:
-
locals: A module block for setting local values, such as the resource group name for easy reuse in complex expressions.
-
resource_group: This block of code retrieves the details of an existing Azure resource group. It uses the resource group name from the local variable set earlier.
-
vnet: Similar to the resource group data block, this block fetches the details of an existing Azure Virtual Network within the specified resource group.
-
subnet: This block creates a subnet in the fetched existing virtual network. It’s using the resource group and virtual network data blocks as well as the subnet details specified in the variables.
-
public_ip: This block creates a new public IP address that will be used by the Azure Firewall. It uses the details specified in the variables and sets the location as the same location of the resource group.
-
firewall: This block creates the Azure Firewall in the same location as the resource group. It sets up the firewall’s SKU configuration and IP configuration. The IP configuration includes the subnet and public IP address created earlier. It also attaches any tags specified in the variables to the firewall.
locals {
rg_name = var.resource_group.name
}
// Get the details of an existing resource group
data "azurerm_resource_group" "resource_group" {
name = local.rg_name
}
// Get the details of an existing virtual network
data "azurerm_virtual_network" "vnet" {
name = var.vnet.name
resource_group_name = local.rg_name
}
// Creating a Subnet
resource "azurerm_subnet" "subnet" {
name = var.subnet.name
resource_group_name = local.rg_name
virtual_network_name = data.azurerm_virtual_network.vnet.name
address_prefixes = var.subnet.address_prefixes
}
// Creating a Public IP Address for Firewall
resource "azurerm_public_ip" "public_ip" {
name = var.public_ip.name
location = data.azurerm_resource_group.resource_group.location
resource_group_name = local.rg_name
allocation_method = var.public_ip.allocation_method
sku = var.public_ip.sku
}
// Creating an Azure Firewall
resource "azurerm_firewall" "firewall" {
name = var.firewall.name
location = data.azurerm_resource_group.resource_group.location
resource_group_name = local.rg_name
// SKU configuration
sku_name = var.firewall.sku_name
sku_tier = var.firewall.sku_tier
ip_configuration {
name = var.firewall.ip_configuration.name
subnet_id = azurerm_subnet.subnet.id
public_ip_address_id = azurerm_public_ip.public_ip.id
}
// Adding tags to the Firewall
tags = var.tags
}
Declaration of input variables #
The variables.tf file in Terraform defines the variables I will use in the main.tf file. These variables allow for more flexibility and reusability in the code.
In this example, the variables are defined in the variables.tf include:
-
resource_group: This variable is an object holding information about the Azure Resource Group where you intend to deploy the resources. The object contains the name of the Resource Group.
-
vnet: This variable is an object that holds information about the existing Azure Virtual Network in which the subnet and firewall will be created. The object requires the name of the Virtual Network and the name of its Resource Group.
-
subnet: This variable will hold the details of the subnet that will be created. The subnet must be named AzureFirewallSubnet and must have a subnet size of /26 or greater.
-
public_ip: This variable will store the details of the public IP address that will be created. It includes the name of the Public IP, the allocation method, and the SKU.
-
firewall: This variable is an object holding the configuration for the Azure Firewall. It includes the name of the firewall, the SKU name, the SKU tier, and an object for the IP configuration which consists of the IP configuration name.
-
tags: This block declares a variable named tags, which is a map of strings. It is used to assign tags to the Azure resources being created. For example, you can use a key-value pair such as Terraform = true to indicate that the resource was deployed with Terraform.
// Variable for the resource group details
variable "resource_group" {
description = "The details of the resource group in which resources will be created"
type = object({
name = string
})
}
// Variable for the virtual network details
variable "vnet" {
description = "The details of the existing virtual network"
type = object({
name = string
})
}
// Variable for the subnet details
variable "subnet" {
description = "The details of the subnet to be created"
type = object({
name = string
address_prefixes = list(string)
})
}
// Variable for the public IP details
variable "public_ip" {
description = "The details of the public IP to be created"
type = object({
name = string
allocation_method = string
sku = string
})
}
// Variable for the Azure firewall
variable "firewall" {
description = "The details of the Azure Firewall to be created"
type = object({
name = string
sku_name = string
sku_tier = string
ip_configuration = object({
name = string
})
})
}
// Variable for tags
variable "tags" {
description = "Common tags for all resources"
type = map(string)
default = {
Environment = "www.jorgebernhardt.com"
Terraform = "true"
}
}
Declaration of output values #
The output.tf file in Terraform extracts and displays information about the resources created or managed by your Terraform configuration. These outputs are defined using the output keyword and can be used to return information that can be particularly helpful for troubleshooting or for referencing these resources in future configurations or scripts.
In this example, the output.tf file returns information about the public ip and Azure firewall resource IDs and names that were created.
Once Terraform has finished applying your configuration, it will display the defined outputs.
// Output the name and public IP address of the firewall
output "firewall_public_ip" {
description = "The name and public IP address of the firewall"
value = {
name = azurerm_public_ip.public_ip.name
ip_address = azurerm_public_ip.public_ip.ip_address
}
}
// Output the name and ID of the firewall
output "firewall_id" {
description = "The name and ID of the firewall"
value = {
name = azurerm_firewall.firewall.name
id = azurerm_firewall.firewall.id
}
}
Executing the Terraform Deployment #
Now that you’ve declared the resources correctly, it’s time to take the following steps to deploy them in your Azure environment.
-
Initialization: To begin, execute the terraform init command. This will initialize your working directory that holds the .tf files and download the provider specified in the provider.tf file, and configure the Terraform backend. I suggest looking at this link if you’re curious about the process.
-
Planning: Next, execute the terraform plan. This command creates an execution plan and shows Terraform’s actions to achieve the desired state defined in your .tf files. This gives you a chance to review the changes before applying them.
-
Apply: When you’re satisfied with the plan, execute the terraform apply command. This will implement the required modifications to attain the intended infrastructure state. Before making any changes, you will be asked to confirm your decision.
-
Inspection: After applying the changes, you can use terraform show command to see the current state of your infrastructure.
-
Destroy (optional): when a project is no longer needed or when resources have become outdated. You can use the terraform destroy command. This will remove all the resources that Terraform has created.
References and useful links #
Thank you for taking the time to read my post. I sincerely hope that you find it helpful.