Project Overview

This project was my attempt at deploying a dynamic, repeatable Azure environment using Infrastructure as Code (IaC). The focus is on deploying multiple virtual machines, enforcing consistent naming conventions, and enabling easy scalability through parameterized configuration.

The article is intended as a project that showcases practical Terraform fundamentals, real-world design thinking, and lessons learned along the way.


Project Background

This project originated from a real-world requirement to support a scalable remote access workload in an enterprise environment.

The infrastructure needed to support multiple server roles (such as remote access servers and network policy servers) and be able to grow over time as demand increased. Rather than treating the deployment as a one-off build, I wanted an approach that allowed the environment to scale predictably for example, adding additional servers by changing a variable instead of manually provisioning new resources.

I used this requirement as an opportunity to learn and apply Infrastructure as Code (IaC) principles with Terraform. The focus of the project is on building a flexible Azure foundation capable of supporting a growing workload, not on the configuration of the remote access solution itself.

All implementation details have been intentionally generalized to avoid exposing any organization-specific or security-sensitive information.


What I Built

Using Terraform, I deployed an Azure environment that includes:

  • An Azure Resource Group
  • A Virtual Network with frontend and backend subnets
  • Multiple Windows Virtual Machines deployed dynamically
  • Network Interfaces with static private IPs
  • An internal Azure Load Balancer
  • Backend pool associations for selected servers
  • Route tables and subnet associations
  • VNet peering to an existing connectivity network

All resources follow a predictable naming convention generated dynamically using Terraform expressions.


Why Terraform?

Terraform was chosen because it allows:

  • Declarative infrastructure definitions
  • Parameter-driven deployments
  • Consistent and repeatable environments
  • Infrastructure to be version-controlled

Instead of manually creating resources through the Azure Portal, the entire environment can be deployed with:

terraform init
terraform plan
terraform apply

This makes rebuilding or scaling the environment both fast and reliable.


Project Structure

The Terraform configuration is split into logical files:

  • main.tf – Core Azure infrastructure such as networking, load balancing, and routing
  • VirtualMachines.tf – Virtual machine and network interface definitions
  • vars.tf – Centralized variable definitions

Separating concerns this way keeps the project easier to read, maintain, and extend.


Deploying Multiple Virtual Machines with Variables

One of the primary goals of this project was to deploy multiple virtual machines without duplicating code. This is achieved using Terraform’s count meta-argument.

Example:

count = var.no_ras_servers

By updating a single variable:

no_ras_servers = 3

Terraform automatically provisions:

  • The required number of network interfaces
  • The corresponding virtual machines
  • Any associated resources such as load balancer backend memberships

This approach makes scaling the environment straightforward and predictable.


Enforcing Consistent Naming Conventions

A key design goal was ensuring all Azure resources follow a consistent naming standard.

Terraform’s format() function is used to dynamically generate names:

name = format("%s%s22%02d", var.server_name_prefix, var.ras_server_name, count.index + 1)

This results in predictable resource names such as:

  • rylabras2201
  • rylabras2202
  • rylabras2203

The same naming logic is applied across:

  • Virtual machines
  • Network interfaces
  • OS disks
  • IP configuration names

Consistent naming improves readability, troubleshooting, and long-term maintainability.


Networking and Load Balancing

The deployed environment includes:

  • A Virtual Network with multiple address spaces
  • Frontend and backend subnets
  • Static private IP assignment for all NICs
  • An internal Standard Azure Load Balancer

Selected servers are automatically added to a backend pool using Terraform associations:

resource "azurerm_network_interface_backend_address_pool_association" "RAS_servers_LB_backend_address_pool" {
  count = var.no_ras_servers
  network_interface_id    = azurerm_network_interface.RAS_servers_nic01[count.index].id
  ip_configuration_name   = azurerm_network_interface.RAS_servers_nic01[count.index].ip_configuration[0].name
  backend_address_pool_id = azurerm_lb_backend_address_pool.RAS_LB_backend_pool_NIC.id
}

Health probes and load balancing rules are defined to ensure traffic is only sent to healthy instances.


State Management

For this project, the Terraform state file is stored locally.

While this is acceptable for learning and solo projects, in production environments a remote backend (such as Azure Storage) would typically be used to:

  • Enable team collaboration
  • Lock state during deployments
  • Improve security and resilience

Lessons Learned

1. Variables Enable Scalability

Parameterizing values such as server counts, locations, and SKUs allows the same Terraform code to adapt to changing requirements.

2. count Eliminates Repetition

Using count reduces duplicated code and makes infrastructure scaling trivial.

3. Naming Standards Matter

Consistent naming conventions simplify automation, troubleshooting, and day-to-day operations.


Future Improvements

If I were to extend this project further, I would:

  • Move the Terraform state to a remote backend
  • Refactor VM logic into reusable modules
  • Add environment separation (dev / test / prod)
  • Integrate CI/CD pipelines
  • Store secrets securely using Azure Key Vault

Final Thoughts

This project was a practical introduction to deploying scalable Azure infrastructure using Terraform. It demonstrates how relatively simple Terraform configurations can create consistent, repeatable, and scalable cloud environments.

For anyone starting out with Terraform, building a small but realistic project like this is an excellent way to develop both technical skills and infrastructure design thinking.


Thanks for reading!