[Avg. reading time: 23 minutes]

Terraform

Features of Terraform

Infrastructure as Code: Terraform allows you to write, plan, and create infrastructure using configuration files. This makes infrastructure management automated, consistent, and easy to collaborate on.

Multi-Cloud Support: Terraform supports many cloud providers and on-premises environments, allowing you to manage resources across different platforms seamlessly.

State Management: Terraform keeps track of the current state of your infrastructure in a state file. This enables you to manage changes, plan updates, and maintain consistency in your infrastructure.

Resource Graph: Terraform builds a resource dependency graph that helps in efficiently creating or modifying resources in parallel, speeding up the provisioning process and ensuring dependencies are handled correctly.

Immutable Infrastructure: Terraform promotes the practice of immutable infrastructure, meaning that resources are replaced rather than updated directly. This ensures consistency and reduces configuration drift.

Execution Plan: Terraform provides an execution plan (terraform plan) that previews changes before they are applied, allowing you to understand and validate the impact of changes before implementing them.

Modules: Terraform supports reusability through modules, which are self-contained, reusable pieces of configuration that help you maintain best practices and reduce redundancy in your infrastructure code.

Community and Ecosystem: Terraform has a large open-source community and many providers and modules available through the Terraform Registry, which makes it easier to get started and integrate with various services.

Use Cases

  • Multi-Cloud Provisioning
  • Infrastructure Scaling
  • Disaster Recovery
  • Environment Management
  • Compliance & Standardization
  • CI/CD Pipelines
  • Speed and Simplicity
  • Team Collaboration
  • Error Reduction
  • Enhanced Security

Install Terraform CLI

<a href="https://developer.hashicorp.com/terraform/downloads"" title="" target="_blank">Terraform Download

Terraform Structure for Azure

Provider Block: Specifies Azure as the cloud provider and authentication method.

provider "azurerm" {
  features {}
  subscription_id = "your-subscription-id"
  tenant_id       = "your-tenant-id"
}

Resource Block: Defines Azure resources like VMs, Storage Accounts, or Virtual Networks.

resource "azurerm_virtual_machine" "example" {
  name                  = "example-vm"
  location              = "East US"
  resource_group_name   = azurerm_resource_group.example.name
  vm_size               = "Standard_DS1_v2"
  
  storage_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }
}

Data Block: Retrieves information about existing Azure resources.

data "azurerm_resource_group" "example" {
  name = "existing-resource-group"
}

data "azurerm_virtual_network" "existing" {
  name                = "existing-vnet"
  resource_group_name = data.azurerm_resource_group.example.name
}

Variable Block: Defines input variables for flexible configuration.

variable "location" {
  description = "The Azure Region to deploy resources"
  type        = string
  default     = "East US"
}

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

Output Block: Returns values after applying the configuration.

output "vm_ip_address" {
  value = azurerm_public_ip.example.ip_address
}

output "storage_account_primary_key" {
  value     = azurerm_storage_account.example.primary_access_key
  sensitive = true
}

Module Block: Reusable components for Azure infrastructure.

module "vnet" {
  source              = "./modules/vnet"
  resource_group_name = azurerm_resource_group.example.name
  location            = var.location
  address_space       = ["10.0.0.0/16"]
}

Locals Block: Local variables for repeated values.

locals {
  common_tags = {
    Environment = var.environment
    Project     = "MyProject"
    Owner       = "DevOps Team"
  }
  
  resource_prefix = "${var.environment}-${var.location}"
}
az login

Get the Subscription ID

Create a new folder
Copy the .tf into it

storage.tf


terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=4.4.0"
    }
  }
}

provider "azurerm" {
  features{  
  
  }
  subscription_id = "your subscription id"
}

# Create a resource group
resource "azurerm_resource_group" "example" {
  name     = "demo-resourcegroup-via-tf"
  location = "East US"
  
  tags = {
    environment = "dev"
  }
}

# Create a storage account
resource "azurerm_storage_account" "example" {
  name                     = "chandr34demo"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  tags = {
    environment = "dev"
  }
}
terraform init 

terraform validate

terraform plan

terraform apply

terraform destroy

Repeat the above steps to create Resource Group, Blob, ADLS, Containers

Remember to install Azure CLI.

az login

# Configure the Azure provider
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "= 4.4.0"
    }
  }
}

# Configure the Microsoft Azure Provider using CLI authentication
provider "azurerm" {
  features {}
  subscription_id = "your subscription id"
}

# Create a resource group
resource "azurerm_resource_group" "example" {
  name     = "gc-example-resources"
  location = "East US"
  
  tags = {
    environment = "dev"
  }
}

# Create a storage account with ADLS Gen2 enabled
resource "azurerm_storage_account" "adls" {
  name                     = "chandr34adlsgen2"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind            = "StorageV2"  # Required for ADLS Gen2
  is_hns_enabled          = true         # This enables hierarchical namespace for ADLS Gen2

  tags = {
    environment = "dev"
    type        = "data-lake"
  }
}

# Create a storage account for Blob storage
resource "azurerm_storage_account" "blob" {
  name                     = "chandr34blobstorage"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind            = "StorageV2"
  is_hns_enabled          = false        # Disabled for regular blob storage

  # Enable blob-specific features
  blob_properties {
    versioning_enabled       = true
    last_access_time_enabled = true
    container_delete_retention_policy {
      days = 7
    }
  }

  tags = {
    environment = "dev"
    type        = "blob"
  }
}

# Create a container in the blob storage account
resource "azurerm_storage_container" "blob_container" {
  name                  = "myblobs"
  storage_account_name  = azurerm_storage_account.blob.name
  container_access_type = "private"
}

# Create a filesystem in the ADLS Gen2 storage account
resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
  name               = "myfilesystem"
  storage_account_id = azurerm_storage_account.adls.id
}

Create a Linux VM with SSH Keys

Create a new folder and continue

vm_ssh.tf

# Provider configuration
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "= 4.4.0"
    }
    tls = {
      source  = "hashicorp/tls"
      version = "~> 4.0"
    }
    local = {
      source  = "hashicorp/local"
      version = "~> 2.0"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = "your subscription id"
}

# Generate SSH key
resource "tls_private_key" "ssh" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

# Save private key locally
resource "local_file" "private_key" {
  content         = tls_private_key.ssh.private_key_pem
  filename        = "vm_ssh_key.pem"
  file_permission = "0600"
}

# Resource Group
resource "azurerm_resource_group" "rg" {
  name     = "ubuntu-vm-rg"
  location = "eastus"
}

# Virtual Network
resource "azurerm_virtual_network" "vnet" {
  name                = "ubuntu-vm-vnet"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  address_space       = ["10.0.0.0/16"]
}

# Subnet
resource "azurerm_subnet" "subnet" {
  name                 = "ubuntu-vm-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}

# Public IP
resource "azurerm_public_ip" "pip" {
  name                = "ubuntu-vm-pip"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  allocation_method   = "Static"
  sku                = "Standard"
}

# Network Security Group
resource "azurerm_network_security_group" "nsg" {
  name                = "ubuntu-vm-nsg"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  security_rule {
    name                       = "SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range         = "*"
    destination_port_range    = "22"
    source_address_prefix     = "*"
    destination_address_prefix = "*"
  }
}

# Network Interface
resource "azurerm_network_interface" "nic" {
  name                = "ubuntu-vm-nic"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.pip.id
  }
}

# Connect the NSG to the subnet
resource "azurerm_subnet_network_security_group_association" "nsg_association" {
  subnet_id                 = azurerm_subnet.subnet.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

# Virtual Machine
resource "azurerm_linux_virtual_machine" "vm" {
  name                = "ubuntu-vm"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  size                = "Standard_D2s_v3"
  admin_username      = "azureuser"
  
  network_interface_ids = [
    azurerm_network_interface.nic.id
  ]

  admin_ssh_key {
    username   = "azureuser"
    public_key = tls_private_key.ssh.public_key_openssh
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts"
    version   = "latest"
  }
}

# Outputs
output "public_ip_address" {
  value = azurerm_public_ip.pip.ip_address
}

output "ssh_command" {
  value = "ssh -i vm_ssh_key.pem azureuser@${azurerm_public_ip.pip.ip_address}"
}

output "tls_private_key" {
  value     = tls_private_key.ssh.private_key_pem
  sensitive = true
}
ssh aazureuser@ip

Create a Linux VM with UserName and PWD

Create a new folder and continue

vm_pwd.tf

# Provider configuration
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "= 4.4.0"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = "your subscription id"
}

# Resource Group
resource "azurerm_resource_group" "rg" {
  name     = "ubuntu-vm-rg"
  location = "eastus"
}

# Virtual Network
resource "azurerm_virtual_network" "vnet" {
  name                = "ubuntu-vm-vnet"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  address_space       = ["10.0.0.0/16"]
}

# Subnet
resource "azurerm_subnet" "subnet" {
  name                 = "ubuntu-vm-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}

# Public IP
resource "azurerm_public_ip" "pip" {
  name                = "ubuntu-vm-pip"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  allocation_method   = "Static"
  sku                = "Standard"
}

# Network Security Group
resource "azurerm_network_security_group" "nsg" {
  name                = "ubuntu-vm-nsg"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  security_rule {
    name                       = "SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range         = "*"
    destination_port_range    = "22"
    source_address_prefix     = "*"
    destination_address_prefix = "*"
  }
}

# Network Interface
resource "azurerm_network_interface" "nic" {
  name                = "ubuntu-vm-nic"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.pip.id
  }
}

# Connect the NSG to the subnet
resource "azurerm_subnet_network_security_group_association" "nsg_association" {
  subnet_id                 = azurerm_subnet.subnet.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

# Virtual Machine
resource "azurerm_linux_virtual_machine" "vm" {
  name                = "ubuntu-vm"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  size                = "Standard_D2s_v3"
  admin_username      = "azureuser"
  admin_password      = "H3ll0W0rld$"
  disable_password_authentication = false
  
  network_interface_ids = [
    azurerm_network_interface.nic.id
  ]

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts"
    version   = "latest"
  }
}

# Output the public IP
output "public_ip_address" {
  value = azurerm_public_ip.pip.ip_address
}
````<span id='footer-class'>Ver 5.5.3</span>
<footer id="last-change">Last change: 2025-10-15</footer>````