Terraform – Build a VM

In this post, we will deploy a VM to Azure using Terraform, in the previous post we deployed the Resource Group and Virtual Network. Now we will build on this to add

  • Virtual network
  • Subnet
  • Network security group
  • Network interface
  • Virtual Machine

At the bottom of the post the full config will be posted, let’s start looking at each section

# Configure the Microsoft Azure Provider.
provider "azurerm" {
  version = "~>1.35"
}

This is the provider block as described here. When running Terraform init, this will instruct to download the Azurerm plugin

# Create a resource group
resource "azurerm_resource_group" "rsg" {
  name     = "ResourceGroup"
  location = "eastus"
}

The resource block will create a resource group within the EastUS region, which all that other resources will be grouped under.

# Create virtual network
resource "azurerm_virtual_network" "vnet" {
  name                = "Vnet"
  address_space       = ["10.0.0.0/16"]
  location            = "eastus"
  resource_group_name = azurerm_resource_group.rsg.name
}

# Create subnet
resource "azurerm_subnet" "subnet" {
  name                 = "Subnet"
  resource_group_name  = azurerm_resource_group.rsg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefix       = "10.0.1.0/24"
}

Virtual machines need to connect to a network, the above first creates a Virtual Network and then assigns a subnet to the network. Notice that the resource_group_name uses an expression azurerm_resource_group.rsg.name, Terraform uses this to get the name of the resource group that is referenced by azurerm_resource_group resource with the name rsg. Also, virtural_network_name is using an expression to retrieve the Virtual Network name.

# Create public IP
resource "azurerm_public_ip" "publicip" {
  name                = "VMPublicIP01"
  location            = "eastus"
  resource_group_name = azurerm_resource_group.rsg.name
  allocation_method   = "Static"
}

To connect to the VM we assign it a public IP address.

# Create Network Security Group and rule
resource "azurerm_network_security_group" "nsg" {
  name                = "NSG"
  location            = "eastus"
  resource_group_name = azurerm_resource_group.rsg.name

  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 = "*"
  }
}

A Network Security Group (NSG) is a stateful firewall, port 22 is needed opened to allow SSH traffic through so that we can connect to the VM.

# Create network interface
resource "azurerm_network_interface" "nic" {
  name                      = "NIC"
  location                  = "eastus"
  resource_group_name       = azurerm_resource_group.rsg.name
  network_security_group_id = azurerm_network_security_group.nsg.id

  ip_configuration {
    name                          = "myNICConfg"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "dynamic"
    public_ip_address_id          = azurerm_public_ip.publicip.id
  }
}

A VM needs a network card, notice that it applies the NSG to the card. In a production network, the NSG is normally applied to the Subnet.

# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {
  name                  = "mVM"
  location              = "eastus"
  resource_group_name   = azurerm_resource_group.rsg.name
  network_interface_ids = [azurerm_network_interface.nic.id]
  vm_size               = "Standard_DS1_v2"

  storage_os_disk {
    name              = "myOsDisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Premium_LRS"
  }

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

  os_profile {
    computer_name  = "VM"
    admin_username = "plankton"
    admin_password = "Password1234!"
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }
}

This is the part of the code which creates the VM.

Complete config

# Configure the Microsoft Azure Provider.
provider "azurerm" {
  version = "~>1.35"
}

# Create a resource group
resource "azurerm_resource_group" "rsg" {
  name     = "ResourceGroup"
  location = "eastus"
}

# Create virtual network
resource "azurerm_virtual_network" "vnet" {
  name                = "Vnet"
  address_space       = ["10.0.0.0/16"]
  location            = "eastus"
  resource_group_name = azurerm_resource_group.rsg.name
}

# Create subnet
resource "azurerm_subnet" "subnet" {
  name                 = "Subnet"
  resource_group_name  = azurerm_resource_group.rsg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefix       = "10.0.1.0/24"
}

# Create public IP
resource "azurerm_public_ip" "publicip" {
  name                = "VMPublicIP01"
  location            = "eastus"
  resource_group_name = azurerm_resource_group.rsg.name
  allocation_method   = "Static"
}


# Create Network Security Group and rule
resource "azurerm_network_security_group" "nsg" {
  name                = "NSG"
  location            = "eastus"
  resource_group_name = azurerm_resource_group.rsg.name

  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 = "*"
  }
}

# Create network interface
resource "azurerm_network_interface" "nic" {
  name                      = "NIC"
  location                  = "eastus"
  resource_group_name       = azurerm_resource_group.rsg.name
  network_security_group_id = azurerm_network_security_group.nsg.id

  ip_configuration {
    name                          = "myNICConfg"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "dynamic"
    public_ip_address_id          = azurerm_public_ip.publicip.id
  }
}

# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {
  name                  = "mVM"
  location              = "eastus"
  resource_group_name   = azurerm_resource_group.rsg.name
  network_interface_ids = [azurerm_network_interface.nic.id]
  vm_size               = "Standard_DS1_v2"

  storage_os_disk {
    name              = "myOsDisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Premium_LRS"
  }

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

  os_profile {
    computer_name  = "VM"
    admin_username = "plankton"
    admin_password = "Password1234!"
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }
}

Leave a Reply