Terraform is an open-source tool used for writing infrastructure as code. This software allows you to create, change and delete infrastructure predictably and safely. In terraform, we have providers which enable us to define the infrastructure for multiple cloud providers and even some local solutions like Virtualbox. Terraform code is written in an HCI language. At first, writing terraform might be a little odd but when you get the hang of it, it becomes effortless to write and read it.
So to head to our problem of having a list of allowed IP ranges we need to integrate into Azure Web App networking to allow traffic to Azure Web App from the allowed range of IPs.
First, let’s define the Yaml file which will hold our ranges.
ip_config:
- name: firstrange
description: "First Range"
cidr: 8.8.8.8/32
range:
start: 8.8.8.8
end: 8.8.8.8
priority: 101
- name: secondrange
description: "Second Range"
cidr: 192.168.0.1/24
range:
start: 192.168.0.1
end: 192.168.0.254
priority: 102
Now that we have our Yaml file we can switch to terraform.
First, let’s create locals.tf like this
locals {
ip_restriction = [
for ip_config in var.authorized_ips : {
name = ip_config["name"]
ip_address = try(ip_config["cidr"], null)
virtual_network_subnet_id = try(ip_config["virtual_network_subnet_id"], null)
service_tag = try(ip_config["service_tag"], null)
priority = ip_config["priority"]
action = "Allow"
headers = try(ip_config["headers"], null)
}
authorized_ips = yamldecode(file("../shared/ip_ranges.yaml"))["ip_config"]
]
In the first part of locals.tf a file, we are creating a mapping of values to variables. In authorized_ips we use yamldecode function to pars our ip_ranges Yaml file.
Now we can create our main.tf which will be in charge of creating an Azure Web App. I will give here an example of configuration from terraform documentation.
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "West Europe"
}
resource "azurerm_service_plan" "example" {
name = "example"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
os_type = "Linux"
sku_name = "P1v2"
}
resource "azurerm_linux_web_app" "example" {
name = "example"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_service_plan.example.location
service_plan_id = azurerm_service_plan.example.id
site_config {}
ip_restriction = local.authorized_ips
}
Let’s extend our solution so it is able to allow services.
First, we need to extend the Yaml file
ip_config:
- name: firstrange
description: "First Range"
cidr: 8.8.8.8/32
range:
start: 8.8.8.8
end: 8.8.8.8
priority: 101
- name: secondrange
description: "Second Range"
cidr: 192.168.0.1/24
range:
start: 2192.168.0.1
end: 192.168.0.254
priority: 102
services:
- name: AzureCloud
description: "Allow Azure Devops to deploy"
service_tag: "AzureCloud"
priority: 401
The next thing that needs to be changed is authorized_ips from locals.tf
locals {
ip_restriction = [
for ip_config in var.authorized_ips : {
name = ip_config["name"]
ip_address = try(ip_config["cidr"], null)
virtual_network_subnet_id = try(ip_config["virtual_network_subnet_id"], null)
service_tag = try(ip_config["service_tag"], null)
priority = ip_config["priority"]
action = "Allow"
headers = try(ip_config["headers"], null)
}
authorized_ips = concat(yamldecode(file("../shared/ip_ranges.yaml"))["ip_config"], yamldecode(file("../shared/ip_ranges.yaml"))["services"])
}
That would be the whole configuration.
Hope it helps you in your adventures in terraform land 🙂