Create Azure resources using Terraform

Mary AjayiMary Ajayi
5 min read

Introduction

This article demonstrates the process of generating an Azure resource group using Terraform, a powerful tool for defining, previewing, and deploying cloud infrastructure. Terraform leverages HashiCorp Configuration Language (HCL) syntax to construct configuration files, allowing users to specify details about their cloud infrastructure, including the cloud provider such as Azure.

The workflow involves creating configuration files that define the desired infrastructure components. These files serve as a blueprint for the resource group creation. Subsequently, Terraform generates an execution plan, offering a preview of the changes before actual deployment. This ensures that users can review and validate modifications before committing them.

By following the steps in this article, you will gain a practical understanding of how to leverage Terraform to orchestrate the creation of Azure resource groups, enabling efficient and controlled infrastructure deployment.

Prerequisites

Before we begin, make sure you have the following prerequisites:

  1. Azure Subscription: You need an active Azure subscription.

  2. Azure CLI: Install the Azure Command-Line Interface to interact with Azure from the command line. If you need help doing this, click here.

  3. Terraform: Install Terraform on your local machine. If you need help doing this, click here.

Step 1: Set Up Azure Authentication

Ensure that your Azure CLI is properly authenticated. Run the following command and follow the prompts:

az login

Step 2: Create a Terraform Configuration File

Create a new directory for your Terraform configuration and navigate into it:

mkdir terraform-rg
cd terraform-rg

Now, create a file named main.tf with the following content:

terraform {

   required_version = ">=0.12"

   required_providers {
     azurerm = {
       source = "hashicorp/azurerm"
       version = "~>2.0"
     }
   }
 }

 provider "azurerm" {
   features {}
 }

 resource "azurerm_resource_group" "test" {
   name     = "acctestrg"
   location = "West US 2"
 }

 resource "azurerm_virtual_network" "test" {
   name                = "acctvn"
   address_space       = ["10.0.0.0/16"]
   location            = azurerm_resource_group.test.location
   resource_group_name = azurerm_resource_group.test.name
 }

 resource "azurerm_subnet" "test" {
   name                 = "acctsub"
   resource_group_name  = azurerm_resource_group.test.name
   virtual_network_name = azurerm_virtual_network.test.name
   address_prefixes     = ["10.0.2.0/24"]
 }

 resource "azurerm_public_ip" "test" {
   name                         = "publicIPForLB"
   location                     = azurerm_resource_group.test.location
   resource_group_name          = azurerm_resource_group.test.name
   allocation_method            = "Static"
 }

 resource "azurerm_lb" "test" {
   name                = "loadBalancer"
   location            = azurerm_resource_group.test.location
   resource_group_name = azurerm_resource_group.test.name

   frontend_ip_configuration {
     name                 = "publicIPAddress"
     public_ip_address_id = azurerm_public_ip.test.id
   }
 }

 resource "azurerm_lb_backend_address_pool" "test" {
   loadbalancer_id     = azurerm_lb.test.id
   name                = "BackEndAddressPool"
 }

 resource "azurerm_network_interface" "test" {
   count               = 2
   name                = "acctni${count.index}"
   location            = azurerm_resource_group.test.location
   resource_group_name = azurerm_resource_group.test.name

   ip_configuration {
     name                          = "testConfiguration"
     subnet_id                     = azurerm_subnet.test.id
     private_ip_address_allocation = "dynamic"
   }
 }

 resource "azurerm_managed_disk" "test" {
   count                = 2
   name                 = "datadisk_existing_${count.index}"
   location             = azurerm_resource_group.test.location
   resource_group_name  = azurerm_resource_group.test.name
   storage_account_type = "Standard_LRS"
   create_option        = "Empty"
   disk_size_gb         = "1023"
 }

 resource "azurerm_availability_set" "avset" {
   name                         = "avset"
   location                     = azurerm_resource_group.test.location
   resource_group_name          = azurerm_resource_group.test.name
   platform_fault_domain_count  = 2
   platform_update_domain_count = 2
   managed                      = true
 }

 resource "azurerm_virtual_machine" "test" {
   count                 = 2
   name                  = "acctvm${count.index}"
   location              = azurerm_resource_group.test.location
   availability_set_id   = azurerm_availability_set.avset.id
   resource_group_name   = azurerm_resource_group.test.name
   network_interface_ids = [element(azurerm_network_interface.test.*.id, count.index)]
   vm_size               = "Standard_DS1_v2"

   # Uncomment this line to delete the OS disk automatically when deleting the VM
   # delete_os_disk_on_termination = true

   # Uncomment this line to delete the data disks automatically when deleting the VM
   # delete_data_disks_on_termination = true

   storage_image_reference {
     publisher = "Canonical"
     offer     = "UbuntuServer"
     sku       = "16.04-LTS"
     version   = "latest"
   }

   storage_os_disk {
     name              = "myosdisk${count.index}"
     caching           = "ReadWrite"
     create_option     = "FromImage"
     managed_disk_type = "Standard_LRS"
   }

   # Optional data disks
   storage_data_disk {
     name              = "datadisk_new_${count.index}"
     managed_disk_type = "Standard_LRS"
     create_option     = "Empty"
     lun               = 0
     disk_size_gb      = "1023"
   }

   storage_data_disk {
     name            = element(azurerm_managed_disk.test.*.name, count.index)
     managed_disk_id = element(azurerm_managed_disk.test.*.id, count.index)
     create_option   = "Attach"
     lun             = 1
     disk_size_gb    = element(azurerm_managed_disk.test.*.disk_size_gb, count.index)
   }

   os_profile {
     computer_name  = "hostname"
     admin_username = "testadmin"
     admin_password = "Password1234!"
   }

   os_profile_linux_config {
     disable_password_authentication = false
   }

   tags = {
     environment = "staging"
   }
 }

Step 3: Initialize Terraform

Run the following command to initialize your Terraform configuration:

terraform init

This command downloads the Azure provider plugin and sets up your working directory.

Step 4: Create a Terraform Execution Plan

Run terraform plan to create an execution plan.

terraform plan -out main.tfplan

Key points:

  • The terraform plan command generates an execution plan without executing it. Instead, it identifies the actions required to implement the configuration specified in your files. This approach enables you to confirm if the execution plan aligns with your expectations before applying any changes to real resources.

  • The optional -out parameter enables you to designate an output file for the plan. Employing the -out parameter ensures that the plan you have reviewed is precisely what gets applied.

Step 5: Apply the Configuration

If the plan looks correct, apply the configuration:

terraform apply main.tfplan

Type "yes" when prompted to confirm. Terraform will provision the Azure Resource Group and the resources.

Step 6: Verify in Azure Portal

Go to the Azure Portal and navigate to the Resource Groups section. You should see the newly created resource group, "acctestrg".

Note: You should see more resources added.

Step 7: Clean Up (Optional)

If you want to remove the resources created by Terraform, run:

terraform destroy

Type "yes" when prompted to confirm.

Conclusion

Congratulations! You've successfully created an Azure Resource Group and some resources in it using Terraform.

This example provides a foundation for expanding your infrastructure as code practices with Terraform on the Azure cloud platform. Explore additional resources and modules to enhance your Azure deployments using Terraform.

1
Subscribe to my newsletter

Read articles from Mary Ajayi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mary Ajayi
Mary Ajayi

I am passionate about all things tech, and I'm always learning new skills and technologies to stay on top of the latest trends. I'm also a team player who loves collaborating with others to create innovative solutions. In my free time, I enjoy coding, creating tech blogs, and seeing movies. I'm always up for a challenge and I'm excited to see what the future holds.