Alberto Morando
June 15, 2017

Bootstrap Azure virtual machine with Terraform


In the previous post of the Microsoft Azure with Terraform series we have described how to setup Terraform Azure backend for managing remote states. In this post, we explore how to spin up an Azure Virtual Machine (VM) with Terraform and how to bootstrap the first simple Web Application.


Azure Cloud Architecture

Before digging into the Terraform HCL (Hashicorp Configuration Languages) for the Azure VM configuration, we create the Azure cloud architecture that we will deploy. Microsoft provides a package of Azure Cloud symbols that can be used for designing our solution. The minimum Azure cloud infrastructure for creating an Azure VM consists of:

  • ‍Azure Resource Group
  • ‍Azure Storage Account
  • ‍Azure Virtual Network (Vnet)
  • ‍Azure Subnet (Subnet)
  • Azure Public ip (PIP)
  • ‍Azure Network Security Group (NSG)
  • ‍Azure Network Interface (NIC)
  • Azure Virtual Machine (VM)
  • ‍Azure OS Disk

The following picture depicts the Azure cloud infrastructure with all the above listed components. We will implement it with Terraform HCL.



 We look now on how to implement this architecture using Terraform HCL.


Azure Resource Group

For the Azure Resource Group, Terraform provides the azurerm_resource_group resource. We use it for our implementation

 The “name” and the “location” keys have variables assigned to them. The variables are declared and defined in separate Terraform .tf files. The resource group resource is configured with a lifecycle for preventing Terraform to destroy it in case we perform the “terraform destroy” command.


Azure Storage Account

For the Azure Storage Account, Terraform provides the azurerm_storage_account resource. We use it for our implementation


Azure Virtual Network and Subnet

The Azure VM shall be created inside an Azure Virtual Network. For the Azure Virtual Network Terraform provides the azurerm_virtual_network resource. For the Azure Subnet Terraform provides the azurerm_subnet resource. We use them for our implementation

For the Vnet the address range is specified by the CIDR that is giving 65536 addresses available for this Network. The subnet CIDR is giving 256 addresses for the subnet. To this example we leave this setup even if we don´t need all these network addresses.


Azure Public IP address

To be able to communicate with the Azure VM we need to have a Public IP address to associate to the  Azure Network Interface . For the Azure Public IP address Terraform provides the azurerm_public_ip resource. We use it for creating the Public IP address we need

Azure gives the possibility to have max 5 static public IP address per region. In our case we must define the IP address as static since Terraform has an issue when using the remote_exec provisioner with dynamic IP address.


Azure Network Security Group

To be able to setup the rules for accessing the Azure VM we need to use the Azure Network Security Group. For the Azure Network Security Group Terraform provides the azurerm_security_group resource. We can use it for setting up the inbound rules for SSH (port 22) and HTTP (port 80).


Azure Network Interface

Using the Azure Network Security Group and the Azure Public IP we can now setup the Azure Network Interface. For the Azure Network Interface Terraform provides the azurerm_network_interface resource. We can now use it for our implementation.

Azure VM and OS Disk

Now we have all the Azure architecture resources to be able to spin up an Azure VM and its OS Disk. For the Azure VM Terraform provides the azurerm_virtual_machine resource. We create a Linux VM with Ubuntu 16.04 LTS version. The OS disk is created at the Azure VM creation as unmanaged disk.


The Linux VM is created and SSH login is used. For creating the SSH keys pair we use ssh-keygen command and we pass to the Linux VM the public key as parameter for the “ssh_keys” list.


Create it

Now we have the following Terraform files based on the described HCL


We can execute the “terraform plan” command

 and “terraform apply” and see if we can create the Azure Linux VM with Terraform.

If we look to the Azure Portal we can see that all the resources have been created

SSH the Azure VM

We can try now to test the Azure Security Group SSH into the virtual machine using the generated ssh key

We access the Azure VM and we validate the Azure Security Group


Bootstrap a Simple Web Application

At this point we have created the Azure VM with all the infrastructure needed. Usually we create such Azure VM with the purpose of running a Web Application on it. Terraform is not the best tool for bootstrapping a Web Application but it can be done using the Terraform provisioners. To be able to do that we need to add the following HCL to the azure_virtual_machine resource.


Terraform uses the provisioner Connection for connecting to the Azure VM using the SSH key. The Terraform provisioner File for copying the bash file to be executed after the Azure VM is created.

The script is installing Apache server for the Web Application. The index.html is also copied into the Azure VM and used after the Apache server is installed

The Terraform provisioner remote_exec invokes the scripts and performs the copy of the index.html file in the /var/www/html/ directory.

If we run “terraform apply” with the Terraform provisioners we create the Azure VM and install and run the Apache server with our index.html file


We can access the web application using the static IP address and validate at the same time the Azure Security Group HTTP inbound rule



In this post, we deployed an Azure VM using Terraform. We used the architecture first approach designing the Azure infrastructure and then implementing it with Terraform HCL. Terraform is also capable to bootstrap applications into Azure infrastructure and we demonstrated it bootstrapping a simple Web application into the new Azure VM using Terraform.