Azure Networking + Terraform

Build Azure Virtual Network with Terraform

Once you understand Azure Virtual Network conceptually, the best next step is to build one with Terraform. This helps turn cloud networking theory into something practical and repeatable.

This page shows a clean Azure VNet Terraform example, explains the important blocks, and gives you a simple starting point you can expand later with subnets, NSGs, route tables, NAT, private endpoints, and hub-and-spoke architecture.

Quick summary

Before going deeper, here is the simplest way to think about Azure VNet Terraform.

What Terraform code that creates an Azure Virtual Network and its subnets.
Why It makes Azure networking repeatable, reviewable, and version controlled.
When Use it whenever you want consistent infrastructure deployment.
Where It fits into landing zones, platform foundations, app environments, and CI/CD pipelines.
Who Cloud, DevOps, platform, and infrastructure teams usually manage it.
How Using the azurerm provider, resource group, virtual network resource, and subnet resources.

Why use Terraform for Azure VNet?

Building VNets manually in the Azure portal works for learning, but Terraform is better when you need consistency, peer review, repeatability, and environment standardization.

  • It keeps network definitions in code.
  • It makes changes reviewable through Git.
  • It reduces manual mistakes.
  • It makes multi-environment builds easier.
  • It fits naturally into CI/CD and platform engineering workflows.
Simple idea: Terraform turns “clicking around to build networking” into a reusable blueprint that your whole team can understand and deploy consistently.

Terraform code

This example creates:

  • an Azure resource group
  • one Azure Virtual Network
  • three subnets inside that VNet
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.100"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "network_rg" {
  name     = var.resource_group_name
  location = var.location
}

resource "azurerm_virtual_network" "vnet" {
  name                = var.vnet_name
  location            = azurerm_resource_group.network_rg.location
  resource_group_name = azurerm_resource_group.network_rg.name
  address_space       = var.vnet_address_space

  tags = {
    environment = var.environment
    managed_by  = "terraform"
    purpose     = "network-foundation"
  }
}

resource "azurerm_subnet" "web" {
  name                 = "web-subnet"
  resource_group_name  = azurerm_resource_group.network_rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.10.1.0/24"]
}

resource "azurerm_subnet" "app" {
  name                 = "app-subnet"
  resource_group_name  = azurerm_resource_group.network_rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.10.2.0/24"]
}

resource "azurerm_subnet" "db" {
  name                 = "db-subnet"
  resource_group_name  = azurerm_resource_group.network_rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.10.3.0/24"]
}

Code breakdown

Terraform block

This defines the Terraform version and AzureRM provider version. Keeping provider versions controlled helps avoid unexpected changes during future runs.

Provider block

The azurerm provider is what Terraform uses to talk to Azure and create resources.

Resource group

Azure resources live inside a resource group, so this is usually one of the first resources created.

Virtual network resource

The azurerm_virtual_network resource creates the VNet itself. The most important part here is the address_space, because this controls the total IP range available to the network.

Subnet resources

Each azurerm_subnet resource creates a subnet inside the VNet. In this example, the web, app, and database layers are separated clearly to support a common three-tier design.

Why this structure is useful

This is a strong beginner-friendly example because it shows that one VNet usually contains multiple subnets with different roles, rather than placing everything into one flat network.

Suggested variables file

A variables file keeps your Terraform code reusable across environments like dev, test, and production.

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

variable "location" {
  description = "Azure region for deployment"
  type        = string
  default     = "South Africa North"
}

variable "vnet_name" {
  description = "Name of the Azure Virtual Network"
  type        = string
}

variable "vnet_address_space" {
  description = "Address space for the Azure Virtual Network"
  type        = list(string)
  default     = ["10.10.0.0/16"]
}

variable "environment" {
  description = "Environment name"
  type        = string
  default     = "dev"
}

Example terraform.tfvars

resource_group_name = "rg-network-dev-san-1"
location            = "South Africa North"
vnet_name           = "vnet-app-dev-san-1"
vnet_address_space  = ["10.10.0.0/16"]
environment         = "dev"

Suggested outputs

Outputs are useful because they expose important values after deployment, which can later be consumed by other modules or pipeline stages.

output "resource_group_name" {
  value = azurerm_resource_group.network_rg.name
}

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

output "vnet_id" {
  value = azurerm_virtual_network.vnet.id
}

output "web_subnet_id" {
  value = azurerm_subnet.web.id
}

output "app_subnet_id" {
  value = azurerm_subnet.app.id
}

output "db_subnet_id" {
  value = azurerm_subnet.db.id
}

How to run it

A simple execution flow looks like this:

terraform init
terraform fmt
terraform validate
terraform plan
terraform apply

In real teams, these steps usually run inside CI/CD after peer review, instead of being executed manually every time.

Good habit: Run terraform fmt and terraform validate before planning. It keeps your code clean and catches basic issues early.

Real-world usage

This basic VNet Terraform pattern can grow into real platform designs.

App environment foundation

A team creates one VNet and standard subnets for web, app, database, and management workloads, then hands those subnet IDs to application teams.

Landing zone module

A platform team builds reusable Terraform modules so each business unit or environment can deploy standardized Azure networking with approved naming, tagging, CIDR ranges, and policies.

Hub-and-spoke networking

The same Terraform approach can later expand into separate hub and spoke VNets, peering resources, firewall routes, and private endpoint subnet patterns.

Important mindset: Start with a clean simple VNet Terraform example, then grow it gradually. Do not try to build every Azure networking feature in one file on day one.

Best practices

  • Keep resource names clear and consistent.
  • Use variables so the code works across environments.
  • Use outputs to expose IDs for later modules.
  • Tag resources for ownership, environment, and purpose.
  • Plan CIDR ranges carefully before deploying.
  • Split networking into modules as the environment grows.
  • Keep VNet, subnets, NSGs, and route logic readable instead of over-compressing the code.
  • Validate and review Terraform plans before applying.
Strong next step: After this VNet example, the natural progression is Azure Subnets Terraform, then NSGs, Route Tables, and VNet Peering.

Common mistakes

  • Using overlapping CIDR ranges that break future peering or hybrid connectivity.
  • Putting too many unrelated resources into one subnet.
  • Hardcoding every value instead of using variables.
  • Skipping outputs and making downstream integration harder.
  • Using unclear names that become confusing later.
  • Mixing too much networking logic into one file before the basics are stable.
Common beginner trap: Just because Terraform can create the VNet does not mean the address plan is good. Good network design still matters before coding.

Frequently asked questions

What Terraform resource creates an Azure VNet?

The azurerm_virtual_network resource creates an Azure Virtual Network.

Can I create subnets in the same file as the VNet?

Yes. That is a good way to learn. In larger environments, teams often split networking into modules for readability and reuse.

Should I use variables for Azure VNet Terraform?

Yes. Variables make your code reusable across environments and help reduce duplication.

What should I learn after Azure VNet Terraform?

A good sequence is Azure Subnets Terraform, Network Security Groups, Route Tables, NAT, Private Endpoints, and VNet Peering.

Summary

Azure VNet Terraform is one of the best practical starting points for learning Azure infrastructure as code. It teaches you how networking is represented in Terraform, how address space and subnets are declared, and how reusable cloud foundations are built in a real platform workflow.

Official Azure documentation

These are the official Microsoft references that support deeper Azure networking and Terraform-related learning.