Last Updated on August 7, 2025 by Arnav Sharma
Terraform by HashiCorp is IaC tool for defining and managing infrastructure as code across various providers, including Azure. It uses a declarative configuration language to model cloud and on-premises resources efficiently. This guide dives into Terraform’s core concepts, such as resource types, modules, and meta-arguments, along with best practices and examples for Azure.
Terraform: The Infrastructure as Code Solution
Terraform enables users to use a high-level configuration language to describe the desired state of their infrastructure, making it easier for teams to manage and automate deployments across multiple cloud providers, including Azure, AWS, GCP etc.
Resource Type: Azure Building Blocks
In Terraform, each infrastructure component is defined as a resource. The resource type specifies the kind of resource you’re managing (e.g., virtual networks, VMs).
Azure VM Example:
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "East US"
}
resource "azurerm_virtual_machine" "example" {
name = "example-vm"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
network_interface_ids = [azurerm_network_interface.example.id]
vm_size = "Standard_DS1_v2"
storage_os_disk {
name = "myosdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
os_profile {
computer_name = "hostname"
admin_username = "testadmin"
admin_password = "Password1234!"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
This configuration defines an Azure Virtual Machine within a resource group, illustrating how to specify a VM size, storage options, and OS settings.
Meta-Arguments: Customizing Resource Behavior
Meta-arguments in Terraform allow users to control the lifecycle behaviors of resources, like defining custom creation or deletion sequences.
Example with depends_on:
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "East US"
}
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
depends_on = [azurerm_resource_group.example]
}
Here, the creation of a virtual network (azurerm_virtual_network) explicitly depends on the prior creation of a resource group (azurerm_resource_group).
Custom Condition Checks: Validation Rules
While Terraform itself does not perform custom condition checks directly within resource blocks, it supports input validation for variables, which can serve a similar purpose.
Variable Validation Example:
variable "location" {
type = string
description = "The Azure location where resources will be created."
validation {
condition = contains(["East US", "West US", "Central US"], var.location)
error_message = "The location must be East US, West US, or Central US."
}
}
This ensures the specified Azure location is one of the accepted values, enhancing error handling and user feedback.
Configuration: The Terraform Blueprint
Terraform configurations are made up of several files containing the desired state of the infrastructure, written in HCL.
Basic Azure Network Configuration:
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "East US"
}
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}
This configuration sets up a resource group and a virtual network in Azure, demonstrating the declarative syntax used to describe infrastructure components.
Modules: Encapsulating and Reusing Configuration
Modules allow users to group resources together into reusable components. Terraform Registry hosts modules for different providers, including Azure.
Using an Azure Module:
module "network" {
source = "Azure/network/azurerm"
version = "2.0.0"
resource_group_name = azurerm_resource_group.example.name
address_space = "10.0.0.0/16"
subnet_prefixes = ["10.0.1.0/24"]
subnet_names = ["subnet1"]
location = "East US"
tags = {
environment = "Test"
}
}
This leverages an Azure networking module to create a network infrastructure, showcasing the ease of reusing predefined configurations.
Data Sources: Querying Existing Resources
Data sources in Terraform allow you to fetch information about existing resources or infrastructure, facilitating dynamic configurations.
Azure Resource Group Data Source:
data "azurerm_resource_group" "example" {
name = "existing-resources"
}
output "resource_group_location" {
value = data.azurerm_resource_group.example.location
}
This data source fetches information about an existing Azure resource group, which can then be used elsewhere in the Terraform configuration.
Resource Dependencies: Managing Order of Creation
Explicit and implicit dependencies in Terraform control the order in which resources are created, updated, or destroyed.
Implicit Dependency Example:
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "East US"
}
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}
The virtual network implicitly depends on the resource group, ensuring the group is created before the network.
Provider Configuration: Setting Up Azure Provider
Providers in Terraform are plugins that interact with the APIs of service providers. The Azure provider requires configuration such as credentials and region.
Azure Provider Example:
provider "azurerm" {
features {}
subscription_id = "your-subscription-id"
client_id = "your-client-id"
client_secret = "your-client-secret"
tenant_id = "your-tenant-id"
}
This configures the Azure provider with necessary authentication details for deploying resources.
Policy as Code: Enforcing Governance
Terraform integrates with policy-as-code solutions, allowing teams to enforce governance and compliance standards across their infrastructure.