Post

A terraform module for Azure Networks

Introduction

Connectivity is crucial for any service that needs to connect with someone, and a resource present in all kinds of environments, whether on-premises or in the cloud, is the Virtual Network.

A virtual network functions similarly to a physical network, complete with OSI layers, protocols, subnets, and so on. The purpose of this post is to demonstrate how to deploy a virtual network and subnets in Azure Cloud using a module written by me. Why? Because writing Terraform modules is fun, and for enterprise companies, it can be beneficial to have full control over a module and its code.

virtual networks

The module

main.tf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
resource "azurerm_virtual_network" "vnet" {
  name                = var.vnet_name
  address_space       = var.address_space
  location            = var.location
  resource_group_name = var.resource_group_name
}

resource "azurerm_subnet" "subnet" {
  count                = length(var.subnets)
  name                 = var.subnets[count.index]["name"]
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = [var.subnets[count.index]["address_prefix"]]

  depends_on = [ azurerm_virtual_network.vnet ]
}

The first resource block, ‘azurerm_virtual_network’, creates a virtual network. It is necessary to specify the resource group name.

The second block, ‘azurerm_subnet’, utilizes the resource group from the virtual network created in the previous step.

This resource employs a trick by utilizing the ‘count’ built-in function to generate a range of subnets that are provided to us as variables. Below are more details about it.

variables.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
variable "vnet_name" {
  description = "Name of the virtual network."
  type        = string
}

variable "address_space" {
  description = "Address space of the virtual network."
  type        = list(string)
}

variable "location" {
  description = "Azure location where the virtual network will be created."
  type        = string
}

variable "resource_group_name" {
  description = "Name of the resource group."
  type        = string
}

variable "subnets" {
  description = "List of subnets to create."
  type        = list(map(string))
}

The trick relies on subnet variables, which receive a list of strings. When we execute this module, I promise it will become clearer.

outputs.tf

1
2
3
4
5
6
7
8
9
10
11
output "vnet_id" {
  value = azurerm_virtual_network.vnet.id
}

output "vnet_name" {
  value = azurerm_virtual_network.vnet.name
}

output "subnet_ids" {
  value = { for s in azurerm_subnet.subnet : s.name => s.id }
}

Nothing new here. Just print the virtual network ID, name, and subnet IDs.

providers.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
terraform {
  required_version = ">=0.12"

  required_providers {

    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}

provider "azurerm" {
  features {}
}

And finally a provider block.

Using module

main.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module "network" {
  source    = "git::https://github.com/rmnobarra/azure-network-terraform-module.git?ref=v1.0.0"
  vnet_name           = "vnet"
  address_space       = ["10.11.0.0/16"]
  location            = "brazilsouth"
  resource_group_name = "develop"
  subnets = [
    {
      name           = "subnet_a"
      address_prefix = "10.11.1.0/24"
    },
    {
      name           = "subnet_b"
      address_prefix = "10.11.2.0/24"
    },
    {
      name           = "subnet_c"
      address_prefix = "10.11.3.0/24"
    }
  ]
}

The source line I pass to the URL module is a Git repository that contains all the .hcl files mentioned above.

The magic lies in the ‘subnets’ variable, which makes subnet creation dynamic by sending a map to the module variable. Beautiful, don’t you think?

outputs.tf

1
2
3
4
5
6
7
8
9
10
11
output "vnet_id" {
  value = module.network.vnet_id
}

output "vnet_name" {
  value = module.network.vnet_name
}

output "subnet_ids" {
  value = module.network.subnet_ids
}

And the outputs block, thats print virtual network id, virtual network name and subnets id.

Run module

After run terraform plan command the output below is expected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.network.azurerm_subnet.subnet[0] will be created
  + resource "azurerm_subnet" "subnet" {
      + address_prefix                                 = (known after apply)
      + address_prefixes                               = [
          + "10.11.1.0/24",
        ]
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + name                                           = "subnet_a"
      + resource_group_name                            = "develop"
      + virtual_network_name                           = "vnet"
    }

  # module.network.azurerm_subnet.subnet[1] will be created
  + resource "azurerm_subnet" "subnet" {
      + address_prefix                                 = (known after apply)
      + address_prefixes                               = [
          + "10.11.2.0/24",
        ]
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + name                                           = "subnet_b"
      + resource_group_name                            = "develop"
      + virtual_network_name                           = "vnet"
    }

  # module.network.azurerm_subnet.subnet[2] will be created
  + resource "azurerm_subnet" "subnet" {
      + address_prefix                                 = (known after apply)
      + address_prefixes                               = [
          + "10.11.3.0/24",
        ]
      + enforce_private_link_endpoint_network_policies = false
      + enforce_private_link_service_network_policies  = false
      + id                                             = (known after apply)
      + name                                           = "subnet_c"
      + resource_group_name                            = "develop"
      + virtual_network_name                           = "vnet"
    }

  # module.network.azurerm_virtual_network.vnet will be created
  + resource "azurerm_virtual_network" "vnet" {
      + address_space         = [
          + "10.11.0.0/16",
        ]
      + dns_servers           = (known after apply)
      + guid                  = (known after apply)
      + id                    = (known after apply)
      + location              = "brazilsouth"
      + name                  = "vnet"
      + resource_group_name   = "develop"
      + subnet                = (known after apply)
      + vm_protection_enabled = false
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + subnet_ids = {
      + subnet_a = (known after apply)
      + subnet_b = (known after apply)
      + subnet_c = (known after apply)
    }
  + vnet_id    = (known after apply)
  + vnet_name  = "vnet"

And virtual network and subnets created in Azure:

virtual network azure

Conclusion

The Terraform module is very handy for sharing reusable infrastructure pieces, and turning those components into products is a great approach for DevOps teams to standardize deliveries. This, once again, emphasizes the importance of turning Infrastructure as Code (IaC) into tangible tech products.

References

This modules lives in https://github.com/rmnobarra/azure-network-terraform-module, be my guest for any pull request.

Any sugests or doubt?

Feel free to reach out to me on social media: twitter ,linkedin and github.

You can also email me directly at rmnobarra@gmail.com.

Support

Did you really enjoy my content? Consider buying me a coffee through my Bitcoins wallets:

Donate with Bitcoin

Bitcoin Wallet:

bc1quuv5hml9fjkf7azgwkt4xp867pzdwzyga33qmj

Bitcoin wallet QRCODE

Donate through Lightning Network

Lighting Address:

lnbc1pjue6mkpp5yj737e7fm6efhlj6sns42a875pmkencqmvdshf4ghlnntaet5llsdqqcqzzsxqrrsssp5d9hxl686w839qkwmkm0m30cf5gp4gnzxh68kss393xqzlsg0wr3q9qyyssqp3933zc3fg46nk3vafh63r3lqd0jn2p04w5xrz77h33rrr3xm7ckegg6s2ss64g4rf4jg87zdjzkl5tup7umqpghy2qnk65tqzsnplcpwv6z4c

Lighting wallet QRCODE

Bye!

This post is licensed under CC BY 4.0 by the author.