Azure Zero to Hero: Getting Started with Terraform for Azure & VS Code Setup
Welcome to the definitive study guide for Day 23 of the Azure Zero to Hero series. This chapter provides a complete, hands-on walkthrough for managing Azure cloud resources using HashiCorp Terraform from within Visual Studio Code. You will learn how to authenticate Terraform with Azure, build a complete multi-tier infrastructure from scratch, migrate your local state file to a centralized Azure Blob Storage backend, and apply production-grade best practices.
1. Why Terraform? The Problem with Manual Operations & Single-Cloud Tools
As a DevOps engineer managing modern cloud infrastructures, you will frequently encounter the temptation—or the pressure—to provision resources using graphical user interfaces or cloud-native scripting tools. However, enterprise reality demands a more unified and scalable approach.
The Problem with the User Interface (UI)
- Strict No-Go for Production: Clicking through the Azure Portal to provision virtual networks, subnets, and virtual machines is acceptable solely for exploratory learning.
- Wasted Effort: Manual clicks are entirely unrepeatable, prone to human error, impossible to track via version control, and useless for automated CI/CD pipelines.
The Problem with Native Cloud Automation Tools
- Platform Fragmentation: Every major cloud provider offers proprietary automation frameworks:
- AWS: CloudFormation Templates (CFT).
- Azure: Azure Resource Manager (ARM) templates, Azure CLI, Azure SDKs, and Bicep.
- GCP / OpenStack / DigitalOcean: Proprietary APIs, heat templates, or custom SDKs.
- The Multi-Cloud Dilemma: If your enterprise runs a multi-cloud architecture (e.g., AWS for AI/ML TensorFlow workloads, Azure for CI/CD pipelines with Azure DevOps, and GCP for Kubernetes GKE clusters), mastering native tools for every provider creates an impossible learning curve and locks you into specific vendor ecosystems.
The Terraform Solution
- Unified Language: Terraform introduces HashiCorp Configuration Language (HCL). You write declarative configuration files in HCL, and Terraform handles communication across dozens of cloud providers.
- Extensibility: Whether you target AWS, Azure, GCP, or Kubernetes, the workflow remains identical. You only need to learn HCL.
2. Core Mental Model: How Terraform Interacts with Azure
To understand how Terraform bridges your local machine with cloud providers, examine the underlying communication flow.
Real-Life Analogy: The Universal Travel Translator
Think of Terraform as a Master Universal Translator who speaks only one language (HCL). Instead of you needing to learn the distinct local dialects and bureaucratic APIs of AWS, Azure, and GCP, you simply speak your requirements to the Translator. The Translator listens to your blueprint, translates it on the fly into the exact API dialect required by Azure or AWS, and ensures your instructions are executed correctly. This is why Terraform is often described as an "API as Code" platform.
3. Infrastructure Architecture: What We Are Building Today
In this hands-on lab, we will provision a complete, production-style Linux virtual machine topology on Azure using Terraform.
4. Setting Up Visual Studio Code and Azure CLI
Before writing any Terraform code, you must ensure your local development environment is correctly configured with Visual Studio Code, the Azure CLI, and essential extensions.
Step 1: Install Visual Studio Code
Download and install VS Code for your operating system (macOS Universal, Windows Installer, or Linux RPM/DEB packages) from the official website.
Step 2: Install Essential VS Code Extensions
Open the Extensions view (Ctrl+Shift+X or Cmd+Shift+X) and install the following verified extensions:
- HashiCorp Terraform: Provides syntax highlighting, autocompletion, and validation for HCL files.
- Azure Terraform: Official Microsoft extension providing specialized tooling for developing Terraform configurations on Azure.
Step 3: Install Azure CLI and Authenticate
Terraform requires active cloud credentials to communicate with Azure. We use the Azure CLI for local authentication.
- Verify if Azure CLI is installed:
BASH
az version - If not installed, download and install the Azure CLI for your operating system from Microsoft's documentation.
- Authenticate your terminal session with Azure:
This command opens a browser window prompting you to sign in. Once authenticated, Azure CLI grants Terraform the authorization permissions associated with your signed-in user account.BASH
az login
5. Writing the Terraform Configuration (main.tf)
Create a working directory (e.g., dummy or day23) and create a file named main.tf. We will define our provider settings and infrastructure resources step-by-step.
Step 5.1: Provider Configuration
Tell Terraform which cloud provider to use and specify the required version of the Azure Resource Manager (azureurm) provider.
terraform {
required_version = ">= 1.0.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
Step 5.2: Complete Infrastructure Definition (main.tf)
Below is the complete, production-ready configuration defining the Resource Group, VNet, Subnet, Public IP, Network Interface, and Ubuntu Virtual Machine with SSH key authentication.
# 1. Create a Resource Group
resource "azurerm_resource_group" "example" {
name = "example-resources-1"
location = "East US"
}
# 2. Create a Virtual Network
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
}
# 3. Create a Subnet
resource "azurerm_subnet" "example" {
name = "internal"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.2.0/24"]
}
# 4. Create a Public IP Address
resource "azurerm_public_ip" "example" {
name = "example-pip"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
allocation_method = "Dynamic"
}
# 5. Create a Network Interface (NIC) attaching Subnet and Public IP
resource "azurerm_network_interface" "example" {
name = "example-nic"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.example.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.example.id
}
}
# 6. Create the Linux Virtual Machine
resource "azurerm_linux_virtual_machine" "example" {
name = "example-machine"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
size = "Standard_B1s"
admin_username = "adminuser"
network_interface_ids = [
azurerm_network_interface.example.id,
]
admin_ssh_key {
username = "adminuser"
public_key = file("~/.ssh/id_rsa.pub")
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
}
Note: If you do not have an SSH key pair generated on your local machine, run
ssh-keygenin your terminal before executing the Terraform script.
6. Executing Terraform Workflows: Init, Plan, and Apply
With your configuration in place, execute the standard three-phase Terraform lifecycle.
Phase 1: Initialization (terraform init)
Initializes the working directory, downloads the required provider plugins (such as azurerm), and sets up local modules.
terraform init
Phase 2: Dry-Run Validation (terraform plan)
Generates and displays an execution plan without making any actual changes to your Azure infrastructure. This acts as a safety check.
terraform plan
Expected Output: Terraform inspects your configuration and reports exactly how many resources will be added (5 to add), changed (0 to change), or destroyed (0 to destroy).
Phase 3: Provisioning Infrastructure (terraform apply)
Executes the actions proposed in the plan to provision resources on Azure.
terraform apply
Prompt: Terraform will prompt you for confirmation (Enter a value: yes). Type yes to proceed.
7. Verifying Deployment & Connecting via SSH
Once terraform apply finishes successfully, you can verify your resources in the Azure Portal or connect directly to your newly created virtual machine.
- Verify in Azure Portal: Navigate to Resource Groups ->
example-resources-1. You will see your Virtual Network, Subnet, NIC, Public IP, and Ubuntu Virtual Machine. - Connect via SSH: Copy the public IP address generated by Azure and run the following command in your terminal:
BASH
ssh -i ~/.ssh/id_rsa adminuser@<YOUR_PUBLIC_IP>Note: If you encounter a permissions error on your private key (e.g.,
Permissions are too open), secure your private key file permissions by running:BASHchmod 600 ~/.ssh/id_rsa
8. State File Management & Remote Backend Migration
By default, Terraform stores a record of your real-world infrastructure in a local JSON file named terraform.tfstate.
Why Local State Files Fail in Enterprise Teams
- No Collaboration: If two engineers run Terraform from their local laptops, their local state files will drift, leading to conflicting infrastructure states.
- Security Risks: Local state files can contain sensitive configuration data (such as IP addresses, tokens, and temporary keys).
- Accidental Deletion: Deleting your local workspace directory destroys the state record, making Terraform lose track of managed resources.
Solution: Migrating State to Azure Blob Storage
To enable team collaboration and centralized security, we migrate the state file to an Azure Storage Account Blob container.
Step 1: Create an Azure Storage Account and Container
- Log into the Azure Portal and create a Storage Account (e.g.,
azbackendabby) in theEast USregion. - Inside the Storage Account, navigate to Containers and create a new container named
backend.
Step 2: Retrieve Storage Account Access Keys
- In your Azure Storage Account menu, navigate to Access keys.
- Click Show on
key1and copy the connection string or access key value.
Step 3: Configure the Remote Backend (backend.tf)
Create a new file named backend.tf in your project directory:
terraform {
backend "azurerm" {
resource_group_name = "example-resources-1"
storage_account_name = "azbackendabby"
container_name = "backend"
key = "terraform.tfstate"
access_key = "<YOUR_STORAGE_ACCOUNT_ACCESS_KEY>"
}
}
Security Note: In production environments, never hardcode access keys in plaintext. Inject them via environment variables or secure secret managers like HashiCorp Vault or Azure Key Vault.
Step 4: Re-initialize to Migrate State
Run terraform init again. Terraform will detect the new backend configuration and prompt you to copy your existing local state file up to Azure Blob Storage:
terraform init
Prompt: Answer yes when asked if you want to copy existing state to the new backend.
9. Industry Best Practices & Interview Quick-Reference
When discussing Terraform and Azure integration in technical interviews, keep these core architectural principles in mind:
10. Summary and Key Takeaways
- Unified Multi-Cloud Management: Terraform uses HashiCorp Configuration Language (HCL) to abstract proprietary cloud APIs (AWS, Azure, GCP), eliminating the need to learn platform-specific tools like ARM templates or Bicep.
- The API as Code Paradigm: Terraform acts as an intelligent translator, converting declarative HCL files into targeted REST API calls against cloud provider resource managers.
- Prerequisite Tooling: Effective development requires VS Code equipped with HashiCorp Terraform and Azure Terraform extensions, alongside an authenticated Azure CLI session (
az login). - Declarative Resource Definition: Resources such as Resource Groups, Virtual Networks, Subnets, Public IPs, NICs, and Virtual Machines are declared in
main.tfand verified usingterraform plan. - SSH Key Authentication: Secure Linux virtual machine access by provisioning public SSH keys directly via
admin_ssh_keyblocks or local key pairs (~/.ssh/id_rsa.pub). - State File Centralization: Local state files (
terraform.tfstate) present severe collaboration and security risks in team environments. - Remote Backend Migration: Production setups migrate state files into secure, centralized cloud storage backends (such as Azure Blob Storage containers) protected by access keys or vault integrations.
- Enterprise Governance: Following modular coding standards, utilizing input variables, and enforcing remote state locking are essential practices for scaling infrastructure as code successfully.