DEV Community

Cover image for Create Azure Virtual Machine (Linux VM) with Terraform
Paschal Ogu
Paschal Ogu

Posted on • Edited on • Originally published at blog.paschalogu.com

Create Azure Virtual Machine (Linux VM) with Terraform

Azure Virtual Machines provide a flexible and scalable solution for running your applications in the cloud. By leveraging Terraform, we can automate the creation and configuration of VMs, ensuring consistency and reproducibility in our deployments. We will specifically focus on Linux VMs, as they are widely used for various purposes, such as web hosting, application deployment, and data analysis.

In this article, we will go through the steps of using Terraform to create an Azure Virtual machine with the following resources: Azure Resource Group, Azure Virtual Network, Network Subnet, Public IP address, Network Security Group, Network Interface, Linux Virtual Machine.

Prerequisites
Install and Configure Azure CLI
Install and Configure Terraform
Provision the Infrastructure on Azure
Destroy the infrastructure
Conclusion

Prerequisites

  • An azure account and subscription: If you don't have an Azure subscription, create a free account before you begin.
  • Infrastructure-as-Code Basics: Basic understanding of infrastructure as code is required to follow along.

Terraform is a declarative open-source “Infrastructure as Code" tool, created by HashiCorp, that enables the definition of on-premises and cloud resources in human-readable configuration files that can be versioned, reused, and shared as code.

Install and Configure Azure CLI

Open a command line from any device that has access to the Azure CLI. For steps on how to configure azure CLI locally, refer to this Microsoft Documentation



sudo apt update
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash


Enter fullscreen mode Exit fullscreen mode

Run the command az --version to confirm this has been installed successfully.

AZ-Login

Install and Authenticate Terraform to Azure

Install Terraform

Depending on your operating system, the command to install terraform may be slightly different. Refer to the terraform documentation for system-specific instruction: Terraform Installation Guide



sudo apt update
sudo snap install terraform --classic 


Enter fullscreen mode Exit fullscreen mode

Run terraform --version command to view the version on terraform installed.



terraform --version


Enter fullscreen mode Exit fullscreen mode

Make a Repository to hold our Terraform files and change the directory to this newly created repository.



mkdir Terraform
cd Terraform


Enter fullscreen mode Exit fullscreen mode

Authenticate Terraform to Azure using a Microsoft Account

You can either authenticate to Azure using a Microsoft account or by using a service principal. In this blog, we will authenticate using a Microsoft account.

Run az login without any parameters and follow the instructions to sign in to Azure. When you log in successful, az login will display a list of the Azure subscriptions associated with the logged-in Microsoft account, including the default subscription.



az login


Enter fullscreen mode Exit fullscreen mode

If you want to use a specific subscription, run the command below to show and set the required subscription.



az account show
az account set --subscription "<subscription_id_or_subscription_name>"


Enter fullscreen mode Exit fullscreen mode

Provision the Infrastructure on Azure

Create a file to provision virtual machine on Microsoft Azure. This file will create following resources: Azure Resource Group, Azure Virtual Network, Network Subnet, Public IP address, Network Security Group, Network Interface, Linux Virtual Machine. We will call the file main.tf.



nano main.tf


Enter fullscreen mode Exit fullscreen mode

Copy and paste the code below into the file created above



provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "main" {
  name     = "${var.prefix}-resources"
  location =  "eastus"
}

resource "azurerm_virtual_network" "main" {
  name                = "${var.prefix}-network"
  address_space       = ["10.0.0.0/22"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

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

resource "azurerm_public_ip" "public_ip" {
  name                = "acceptanceTestPublicIp1"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  allocation_method   = "Dynamic"
}

resource "azurerm_network_interface" "main" {
  name                = "${var.prefix}-nic"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

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

resource "azurerm_network_security_group" "nsg" {
  name                = "ssh_nsg"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  security_rule {
    name                       = "allow_ssh_sg"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
  security_rule  {
    name                       = "allow_publicIP"
    priority                   = 103
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "80"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

resource "azurerm_network_interface_security_group_association" "association" {
  network_interface_id      = azurerm_network_interface.main.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

resource "azurerm_linux_virtual_machine" "main" {
  name                            = "${var.prefix}-vm"
  resource_group_name             = azurerm_resource_group.main.name
  location                        = "eastus"
  size                            = "Standard_D2s_v3"
  admin_username                  = "adminuser"
  admin_password                  = "The$admin#password"
  disable_password_authentication = false
  network_interface_ids = [
    azurerm_network_interface.main.id,
  ]

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

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


Enter fullscreen mode Exit fullscreen mode

Remember to change the admin password to a string with your desired password (e.g. admin_password = "253P@assWord!@#".

Next, create a terraform variable file with name variable.tf



variable "prefix" {
  description = "The prefix which should be used for all resources in this example"
}

variable "location" {
  description = "eastus"
} 


Enter fullscreen mode Exit fullscreen mode

Run Terraform init to initialize the repository.

terraform-initn

To see changes that will take effect before any action run terraform plan.



terraform plan


Enter fullscreen mode Exit fullscreen mode

When prompted for location, enter your preferred location e.g. eastus

When prompted for prefix, enter the prefix that will be prepended to all resources created by terraform.

terraform-plan

To apply the changes to our Azure environment, run the command below terraform apply to apply the changes. This should go off and provision the resources in your azure cloud environment.



terraform apply


Enter fullscreen mode Exit fullscreen mode

terraform-apply

To see a list of resources provisioned, run the terraform state list command.



terraform state list


Enter fullscreen mode Exit fullscreen mode

terraform-state-list

Destroying the infrastructure

Run the below command and type yes to destroy the infrastructure



terraform destroy


Enter fullscreen mode Exit fullscreen mode

Conclusion:

In this article, we harnessed the power of Terraform for infrastructure as code to provision resources on Azure. Firstly, we installed and configured Azure CLI on local device, installed and authenticated Terraform to provision infrastructure and resources on Azure. At the end, we destroyed the infrastructure to avoid incurring much cost.

Thanks for reading. Let me know if you found this helpful. You are welcome to follow me on LinkedIn → Paschal Ogu and Twitter → Paschal_ik.

Coming Up Next:

  • Configure Apache web server on Linux Virtual Machine using Ansible
  • Enable SSL on a Custom Domain
  • Install LAMP STACK on an Azure Virtual machine

References:

Top comments (0)