Terraform logo

Sometimes I need to spin up a virtual machine to quickly test something out on a 'vanilla' machine, for example, to test out a Chocolatey package that I maintain.

Most of the time I log in to the Azure Portal and click around to create a VM. The addition of the choice to use the Azure Virtual Machine with preset configuration does make it a bit easier, but it's still lots of clicking. Maybe I should try automating this!

There are a few choices for automating, but seeing as I've been using Terraform lately I thought I'd try that out, together with Terraform Cloud. As I'll be putting the Terraform files in a public repository on GitHub, I can use the free tier for Terraform Cloud.

You can find the source for the Terraform files at https://github.com/flcdrg/terraform-azure-vm/.

You'll also need to have both the Azure CLI and Terraform CLI installed. You can do this easily via Chocolatey:

choco install terraform
choco install azure-cli

Setting up Terraform Cloud Workspace with GitHub

  1. Log in (or sign up) to Terraform Cloud at https://app.terraform.io, select (or create) your organisation, then go to Workspaces and click on Create a workspace Terraform Cloud - Workspaces tab
  2. Select how you'd like to trigger a workflow. To keep things simple, I chose Version control workflow Terraform Cloud - Create a new workspace
  3. Select the version control provider - Github.com. Alt text
  4. You will now need to authenticate with GitHub. Alt text
  5. Watch out if you get a notification about a pop-up blocker. Alt text If you do, then enable pop-ups for this domain Alt text
  6. Choose which GitHub account or organisation to use: Alt text
  7. Select which repositories should be linked to Terraform Cloud. Alt text
  8. If you use multi-factor authentication then you'll need to approve the access. Alt text
  9. Now that your GitHub repositories are connected, you need to select the repository that Terraform Cloud will use for this workspace. Alt text
  10. Enter a workspace name (and optionally a description) Alt text
  11. Now your workspace has been created! Alt text

You're now ready to add Terraform files to your GitHub repository. I like to use the Terraform CLI to validate and format my .tf files before I commit them to version control.

After adding versions.tf file that contains a cloud definition (along with any providers), you can run terraform login

terraform {
  cloud {
    organization = "flcdrg"
    hostname     = "app.terraform.io"

    workspaces {
      name = "terraform-azure-vm"
    }
  }

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.39.1"
    }
    random = {
      source  = "hashicorp/random"
      version = "3.4.3"
    }
  }
}

provider "azurerm" {
  features {}
}

A browser window will launch to allow you to create an API token that you can then paste back into the CLI. Terraform Cloud - Create API Token dialog

The next thing we need to do is create an Azure service principal that Terraform Cloud can use when deploying to Azure.

In my case, I created a resource group and granted the service principal Contributor access to it (assuming that all the resources you want Terraform to create will live within that resource group). You could also allow the service principal access to the whole subscription if you prefer.

az login
az group create --location westus --resource-group MyResourceGroup
az ad sp create-for-rbac --name <service_principal_name> --role Contributor --scopes /subscriptions/<subscription_id>/resourceGroups/<resourceGroupName>

Now go back to Terraform Cloud, and after selecting the newly created workspace, select Variables.

Under Workspace variables, click Add variable, then select Environment variables. Add a variable for each of the following (for ARM_CLIENT_SECRET also check the Sensitive checkbox), for the value copy the appropriate value from the output from creating the service principal:

  • ARM_CLIENT_ID - appId
  • ARM_CLIENT_SECRET - password
  • ARM_SUBSCRIPTION_ID - id from az account show
  • ARM_TENANT_ID

Workspace variables

With those variables set, you can now push your Terraform files to the GitHub repository.

The Terraform Cloud workspace is configured to evaluate a plan on pull requests, and on pushes or merges to main it will apply those changes.

Terraform Cloud - Plan

By default, you need to manually confirm before 'apply' will run (you can change the workspace to auto-approve to avoid this). Confirm Plan dialog

After a short wait, all the Azure resources (including the VM) should have been created and ready to use. Terraform Cloud - changes applied

Virtual machine password

I'm not hardcoding the password for the virtual machine - rather I'm using the Terraform random_password resource to generate a random password. The password is not displayed in the logs as it is marked as 'sensitive'. But I will actually need to know the password so I can RDP to the VM. It turns out the password value is saved in Terraform state, and you can examine this via the States tab of the workspace.

Terraform Cloud - Workspace state

With that, I'm now able to navigate to the VM resource in the Azure Portal and connect via RDP and do what I need to do.

If you wanted to stick with the CLI, you can also use Azure PowerShell to launch an RDP session.

Extra configuration

If you review the Terraform in the repo, you'll notice I also make use of the azurerm_virtual_machine_extension resource to run some PowerShell that installs Chocolatey. That just saves me from having to do it manually. If you can automate it, why not!

Cleaning up when you're done

For safety, the virtual machine is set to auto shutdown in the evening, which will reduce any costs. To completely remove the virtual machine and any associated storage you can run a "destroy plan"

From the workspace, go to Settings, then Destruction and deletion, and click Queue destroy plan.

Alt text