Featured image of post Terraform on Azure: Introduction and Core Concepts

Terraform on Azure: Introduction and Core Concepts

Explore the fundamentals of Terraform on Azure and learn how to streamline your cloud deployments. This introductory guide covers core concepts and sets the stage for mastering Infrastructure as Code on Azure.

Introduction

If you’re an Azure Administrator or a Cloud Engineer, you’ve probably spent a lot of time in the Azure Portal. It’s a great tool—it gives you visibility, makes resource management intuitive, and helps you spin up infrastructure quickly.

For small-scale setups, the portal works just fine. Click a few buttons, fill in some fields, and your resources are up and running.

But what happens as your infrastructure grows?

Let’s say you need to deploy dozens of virtual machines, make changes across multiple resources at once, or ensure consistent configurations across development, staging, and production environments. Suddenly, the manual approach reveals its limitations:

  • It takes time – Repeating the same steps for every resource becomes tedious
  • It’s error-prone – Small differences in settings lead to inconsistencies
  • Tracking changes is difficult – When requirements change mid-deployment, ensuring every resource gets updated correctly becomes a challenge
  • Consistency suffers – Maintaining identical configurations across environments becomes nearly impossible

What worked perfectly for one or two resources now becomes a significant bottleneck. You find yourself wondering if there’s a way to automate these repetitive tasks while maintaining control over your infrastructure.

This is where many Azure professionals hit a wall—feeling the frustration of scaling limitations while knowing there must be a better approach.

Fortunately, there is a better way to manage growing infrastructure—one that helps you avoid repetitive tasks and maintain consistency. This approach is called Infrastructure as Code (IaC), and it’s transforming how teams manage their cloud resources.

In this article, we’ll explore:

  • The evolution from manual management to automation through scripting
  • How Azure Resource Manager (ARM) templates started solving these challenges
  • Why Terraform has become a popular choice for infrastructure automation
  • The core concepts that make Terraform powerful yet approachable

By the end of this article, you’ll understand how Terraform fits into your Azure workflow and be ready to apply it in your environment—transforming how you manage infrastructure while building on the Azure knowledge you already have.

Let’s dive in!

First Steps into Automation: Scripting

After experiencing the limitations of manual deployments we discussed earlier, most Azure professionals naturally turn to PowerShell or Azure CLI scripting as their first step toward automation.

The appeal is immediate. Instead of clicking through multiple screens to create a virtual machine, you can write a script:

1
2
3
4
5
# Create a new VM
New-AzVM -ResourceGroupName "prod-rg" `
         -Name "web-server" `
         -Location "East US" `
         -Size "Standard_D2s_v3"

One command, and your VM is created! Even better, you can:

  • Save these commands in a script file
  • Run them whenever you need
  • Share them with your team
  • Modify them easily when requirements change

Why Scripting Feels Like a Game-Changer

At first, scripting seems to solve all the portal’s problems:

  • No more clicking through multiple screens
  • No more manual, repetitive work
  • You can automate entire deployments
  • You can ensure consistency across deployments

Imagine deploying ten identical VMs. In the portal, that’s a lot of clicking. With a script? Just change a number and repeat the command, and you’re done.

When Scripting Starts to Show Its Limits

But as your Azure environment grows more complex, you start noticing some challenges. Let’s say you write a script to deploy a complete environment:

  • A couple of virtual machines
  • A virtual network with multiple subnets
  • A load balancer
  • Some storage accounts

The script works great! But then interesting situations start to arise:

Scenario 1: Partial Deployments
You run your script, but it fails halfway through. Now you have:

  • Some resources that were created
  • Others that weren’t
  • No easy way to know what’s missing
  • No automatic cleanup of partial deployments

Unlike the portal where you might have a clearer view of what succeeded and failed, scripts just stop—leaving you with an incomplete deployment.

Scenario 2: Making Changes
Your team needs to modify some settings across all VMs. You run your script again, but:

  • How does the script know what’s already there?
  • Should it modify existing resources or create new ones?
  • What if some settings should change but others should stay the same?

Let’s see what happens when you need to update an existing VM:

First run: Creates “web-server” VM with size “Standard_D2s_v3” Later, you need to change the VM size to “Standard_D4s_v3”

When you modify your script and run it again:

  • The script tries to create “web-server” again
  • You get an error: “Resource ‘web-server’ already exists”
  • Your size change doesn’t get applied

To actually update the VM, you’d need a different approach:

  1. First check if the VM exists
  2. If it exists, use a separate update command
  3. If it doesn’t exist, create it

What started as a simple script is becoming more complex with additional logic just to handle existing resources.

Scenario 3: Multiple Environments
You need to maintain different environments (development, testing, production):

  • Each script needs environment-specific configurations
  • Changes need to be replicated across environments
  • Keeping scripts synchronized becomes a challenge
  • Small differences between environments start creeping in

The Core Challenge: State Management

What you’re discovering is a fundamental limitation of scripting: scripts don’t inherently understand the current state of your infrastructure. They just execute commands in sequence.

When you run a script, it doesn’t:

  • Check what resources already exist
  • Compare existing configurations with desired ones
  • Only apply necessary changes
  • Maintain a record of what it deployed

This limitation becomes more apparent as your infrastructure grows. Teams found themselves writing more scripts to:

  • Check if resources exist before creating them
  • Track what was deployed where
  • Handle different environments
  • Manage dependencies between resources

It was clear that while scripting was a step forward from manual deployment, teams needed a more structured way to manage their growing cloud infrastructure.

This realization led to the development of a different approach altogether—one that would focus on describing your infrastructure rather than writing steps to create it. This approach would come to be known as Infrastructure as Code (IaC).

Infrastructure as Code: A Different Way of Thinking

Remember the state management challenge we discovered with scripting? Teams needed a solution that would:

  • Track existing resources automatically
  • Make changes safely without creating duplicates
  • Apply consistent configurations across different environments
  • Understand resource relationships (like creating networks before VMs)

This is where Infrastructure as Code (IaC) comes in. Instead of writing scripts with step-by-step instructions (the imperative approach), IaC lets you describe the desired end state (the declarative approach).

Understanding the IaC Approach

Let’s say you want two virtual machines for your web application. With IaC, you write a configuration file that looks something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# This Terraform code declares:
# - A web application with 2 identical VMs
# - Located in East US
# - Using a specific VM size
webserver_cluster {
  name = "web-app"
  vm_count = 2
  vm_size = "Standard_D2s_v3"
  location = "East US"
}

This might look similar to a script, but there’s a crucial difference. When you apply this configuration:

  • IaC tools check what already exists in your environment
  • They compare that with what you’ve described
  • They make only the necessary changes to match your description
  • They track everything in a state file that remembers what was deployed

The Power of State Management

Remember trying to track what your scripts deployed? IaC tools handle this automatically. Their state management:

  • Keeps a detailed inventory of every resource
  • Knows the current settings of each resource
  • Understands relationships between resources
  • Updates this information after every change

This means when you want to change something—say, add another VM or modify settings—the tool knows exactly what’s already there and what needs to change.

Safe, Repeatable Deployments

One of the most powerful features of IaC is that you can apply the same configuration multiple times safely. When you do:

  • Nothing happens if everything already matches your description
  • Only necessary changes are made if things are different
  • No accidental duplicates are created
  • No manual checking required

This property—where running the same configuration multiple times produces the same result—is called “idempotency.” It’s what makes IaC tools so reliable for managing infrastructure at scale.

Idempotency: A key property of IaC tools is that you can apply the same configuration multiple times safely, always reaching the same end state regardless of the starting point.

Making Changes Confidently

Want to modify your infrastructure? Just update your configuration:

1
2
3
4
5
6
7
# Updated configuration: Scaling from 2 to 3 VMs
webserver_cluster {
  name = "web-app"
  vm_count = 3  # Changed from 2 to 3
  vm_size = "Standard_D2s_v3"
  location = "East US"
}

When you apply this:

  • The IaC tool sees you want 3 VMs instead of 2
  • It finds the existing VMs in its state file
  • It adds just one new VM to match your description
  • Everything else stays the same

No need to write special logic to check what exists or handle updates. The tool handles all of that for you.

Managing Multiple Environments

Remember the challenge of keeping different environments in sync? With IaC:

  • Use the same configuration files for all environments
  • Change only the necessary values (like VM sizes or counts)
  • Be confident that dev, test, and production share the same structure
  • Track all differences in version control

Your infrastructure becomes like any other code—versioned, reviewed, and consistently deployed.

This approach to managing infrastructure was so powerful that Microsoft built it into Azure through ARM templates. But as we’ll see in the next section, while ARM templates were a step forward, teams still faced challenges using them effectively.

Azure Resource Manager: The Foundation of Azure Automation

As teams started embracing Infrastructure as Code, Microsoft introduced a fundamental change to Azure: Azure Resource Manager (ARM). But to understand why this matters, let’s break down what ARM actually is.

What is Azure Resource Manager?

Think of ARM as Azure’s control center. It’s the system that:

  • Handles every request to create, update, or delete resources
  • Makes sure only authorized people can make changes
  • Ensures resources are deployed consistently
  • Organizes resources into logical groups

In fact, everything you do in Azure goes through ARM:

  • Clicking buttons in the Portal? ARM handles it.
  • Running PowerShell commands? They talk to ARM.
  • Using the Azure CLI? ARM processes those requests.

Azure Resource Manager (ARM)

This centralized approach means every change to your Azure infrastructure follows the same rules and checks, regardless of how you make that change.

Enter ARM Templates

To help teams adopt Infrastructure as Code, Microsoft created a specific JSON-based format called ARM templates. These templates let you describe your desired infrastructure in a way that the Azure Resource Manager system can understand.

Here’s a simple example of an ARM template:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "name": "mystorageaccount",
      "location": "East US",
      "sku": {
        "name": "Standard_LRS"
      }
    }
  ]
}

At first, ARM templates seemed to solve many infrastructure challenges:

  • They work directly with Azure’s Resource Manager system—no extra tools needed
  • They ensure resources are created consistently
  • They understand dependencies (like creating networks before VMs)
  • They can be saved and reused for future deployments

When ARM Templates Started Showing Their Limits

However, as teams started using ARM templates more extensively, they encountered practical challenges:

Complex JSON Structure
Even our simple storage account example requires specific JSON formatting. Now imagine defining an entire application environment with multiple VMs, networks, and storage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{                                          ← Opening brackets begin to stack up
  "resources": [                           ← as your template grows larger
    {
      "properties": {
        "networkProfile": {                ← Deeply nested properties become
          "networkInterfaces": [           ← difficult to follow
            { ... }
          ]
        }
      }
    }
  ]
}                                          ← One misplaced bracket breaks everything

This led to several challenges:

  • Templates quickly become long and difficult to read
  • Even small changes require careful attention to brackets and formatting
  • A single misplaced comma can break the entire template
  • Finding errors in large templates becomes time-consuming

Hard to Maintain and Update
As infrastructure needs grew, teams found themselves:

  • Managing multiple large template files
  • Spending more time fixing JSON syntax than actually building infrastructure
  • Having trouble making quick changes without breaking something
  • Needing to repeat similar configurations in multiple places

Teams needed the power of ARM’s management capabilities but wanted a simpler way to define their infrastructure—a way that would be easier to read, write, and maintain.

ARM’s Important Role

Despite the challenges with ARM templates, the Azure Resource Manager system itself was a crucial advancement. It established:

  • A consistent way to manage Azure resources
  • Protection against unauthorized changes
  • Proper ordering of resource deployment (like networks before VMs)
  • Reliable and predictable deployments

The challenge wasn’t with ARM itself—it was with how we wrote templates to work with it. What teams needed was a more user-friendly way to define infrastructure while still leveraging all the benefits of Azure Resource Manager.

Enter Terraform: Making Infrastructure Code More Human-Friendly

After seeing the challenges with both scripting and ARM templates, you might be wondering: “Isn’t there a way to get the best of both worlds?” This is exactly what Terraform offers—a way to define infrastructure that’s both powerful and easy to read.

How Terraform Makes Things Different

Let’s look at that same storage account we saw earlier, but written in Terraform’s HashiCorp Configuration Language (HCL):

1
2
3
4
5
6
resource "azurerm_storage_account" "example" {
  name                = "mystorageaccount"
  location            = "East US"
  account_tier        = "Standard"
  account_replication_type = "LRS"
}

Compare this to the ARM template version:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "name": "mystorageaccount",
      "location": "East US",
      "sku": {
        "name": "Standard_LRS"
      }
    }
  ]
}
Aspect ARM Templates Terraform
Format JSON (deeply nested) HCL (flatter, more readable)
State Management Partial (deployment history) Comprehensive (detailed state tracking)
Syntax Complexity High (brackets, formatting) Lower (minimal special characters)

Notice the differences:

  • No complex JSON formatting
  • No nested brackets to manage
  • Settings are clearly laid out
  • Names are easy to understand (notice the “azurerm” prefix indicating the Azure provider)

But Terraform isn’t just about nice-looking code. Remember those challenges we discussed with scripting and ARM templates? Terraform actually solves them.

Solving the State Management Problem

The first major challenge Terraform solves is state management. It does this by maintaining what’s called a “state file” that:

  • Keeps track of everything it creates
  • Knows the current settings of each resource
  • Understands relationships between resources
  • Updates automatically when changes are made

Making Changes Safely

Want to move that storage account to a different region? Just update the location:

1
2
3
4
5
6
resource "azurerm_storage_account" "example" {
  name                = "mystorageaccount"
  location            = "West US"  # Changed from East US to West US
  account_tier        = "Standard"
  account_replication_type = "LRS"
}

Before making any changes, Terraform:

  1. Checks its state file to see what’s already deployed
  2. Compares it with the changes you made
  3. Makes only the necessary changes (in this case, just updating the location)
  4. Updates its state file with the new configuration

No accidental duplicates, no need to manually check what exists, and no complex syntax to manage.

Where Does That Leave ARM?

Here’s something important to understand: Terraform doesn’t replace Azure Resource Manager—it works with it. When you use Terraform with Azure:

  • You write your infrastructure code in Terraform’s more readable language (HCL)
  • The Azure provider for Terraform translates your code into the API calls that ARM understands
  • ARM handles the actual deployment of resources
  • Terraform tracks everything in its state file

Think of Terraform as your friendly translator:

  • You communicate in a clear, simple language (HCL)
  • Terraform handles the complex translation to ARM’s API requirements
  • You get the best of both worlds: Terraform’s user-friendly syntax with ARM’s powerful management capabilities

This combination gives you:

  • The readability and simplicity of Terraform’s syntax
  • The power and reliability of ARM’s deployment system
  • The safety of Terraform’s state management

And this is just a glimpse of what Terraform can do. Throughout this series, you’ll discover how Terraform provides even more powerful features that will help you manage your growing infrastructure with confidence.

Looking Ahead: Your Journey with Terraform

In this article, we’ve taken a journey through the evolution of infrastructure management in Azure:

  • We started with the familiar territory of the Azure Portal
  • Explored how scripting offered our first taste of automation
  • Saw how Infrastructure as Code changed the game
  • Learned about ARM’s role in Azure
  • And discovered how Terraform brings it all together with a more approachable solution

You’ve seen how Terraform addresses the key challenges that Azure administrators face:

  • No more clicking through portals for repetitive deployments
  • No more worrying about scripts duplicating resources
  • No more wrestling with complex JSON templates
  • No more manually tracking what’s deployed where

By adopting Terraform, you’ll gain:

  • Faster, more reliable deployments
  • Easier collaboration with your team through version-controlled infrastructure
  • Consistent environments across development, testing, and production
  • The ability to scale your infrastructure management as your needs grow

What you’ve learned here provides a solid foundation, but there’s more to discover. In the upcoming articles, we’ll guide you through the practical steps of working with Terraform in Azure:

Part 2: Getting Started with Terraform in Azure

  • Setting up your development environment with the necessary tools
  • Writing and understanding your first Terraform configuration
  • Deploying your first resources to Azure
  • Mastering the core Terraform workflow: init, plan, apply

Part 3: Your First Real-World Project

  • Building a complete multi-resource environment
  • Implementing resource dependencies and relationships
  • Organizing your configurations for maintainability
  • Applying infrastructure best practices from day one

Part 4: Advanced Terraform Concepts

  • Managing state files securely in team environments
  • Creating flexible configurations with variables and outputs
  • Building reusable components with Terraform modules
  • Managing multiple environments with workspaces

The learning curve might seem steep at first, but each concept builds naturally on what you’ve already learned. By the end of this series, you’ll have all the tools you need to manage your Azure infrastructure efficiently, consistently, and confidently.

Ready to start your hands-on Terraform journey? Head to Part 2: Getting Started with Terraform in Azure where we’ll help you set up your environment and deploy your first resource with Terraform.