I’ve been using Terraform Cloud to create Azure Environments for some time, and in this post, I wanted to share an overview of Terraform Cloud, the prerequisites for deploying Azure environments using it, and provide additional resources to help get started. Note – this article is not exhaustive, and there are other ways of getting started and different potential setups – this is just based on my approach and experience. I’ve also written this article to bring together lots of bits of information that are available in other locations, guides, and sites – to create a reference point.
✅ If you are just getting started with Terraform for Azure – why not check out my Azure Terraform Walkthrough Series here?
What is Terraform Cloud?
Terraform Cloud is a hosted version of Terraform, by HashiCorp, that provides the following key features (and more – this is just a few that are key for me!):
-
A centralised cloud service to run Terraform – including version and state file management.
-
Cost estimation – very handy, but especially for Lab environments where budgets may also be constrained!
-
Easy and secure and collaboration on IAC projects.
-
Simple setup and management, with integration into Version Control Systems.
-
Cost effective usage of Terraform – most lab environments will fit within the free tier.
The benefits of Remote State Management
One of the huge benefits of using Terraform Cloud is Remote State Management, which takes away the challenge of managing Storage, Backup, and configuring manual security for the State File – within Terraform Cloud, Remote State Management takes care of these tasks, reducing the overhead that State Management brings using other tooling that requires setup and configuration of remote State Storage.
You can read more about Remote State Management and State in Terraform Cloud here:
- https://developer.hashicorp.com/terraform/cloud-docs/overview#remote-state-management-data-sharing-and-run-triggers
- https://developer.hashicorp.com/terraform/cloud-docs/workspaces/state
How I work with Terraform Cloud – deploying Azure Lab and Demo Environments
For my lab and demo environments, the diagram below shows how I am using a combination of Visual Studio Code, GitHub, Terraform Cloud, and Microsoft Azure for deployment.
I have Terraform Cloud configured to run a plan whenever a commit is made on the GitHub repo – so I can fix any errors I’ve made in the code! However, all deployment to my Azure Subscription requires a manual confirmation to start the apply phase.
In production environments this process is likely to be expanded across Development/Test/UAT environments and with more automated approvals, but for my lab setup, this setup is simple and serves my needs well.
Pricing
For a full overview of pricing and plans – see here: https://developer.hashicorp.com/terraform/cloud-docs/overview
Getting Started – The Prerequisites
Getting started with Terraform Cloud for Azure is really easy, and there are numerous resources, blogs, and guides to help. At a basic level, to start you will need the following in place:
-
An Azure Subscription
-
A Terraform Cloud Account – sign in or sign up here.
-
A Repository to store code – I am using GitHub. For a guide on creating a repo, see here.
-
Tooling to edit code – I am using Visual Studio Code
-
Code to deploy – if you need sample environment, you can download my Sample Lab here.
-
Service Principal Details – so that Terraform Cloud can interact with Azure.
Creating a Service Principal
A Service Principal in Azure provides an identity that we can use to allow services to interact with our Azure environment. The Service Principal is a set of credentials (which should be treated as sensitive), that are usually added to another system – in our case, Terraform Cloud. You can read more about and how to create a Service Principal here.
Creating a Service Principal is straightforward, and I’m using an Azure CLI command to do this:
az ad sp create-for-rbac -n tfc-demo-lab-env --role Contributor --scopes /subscriptions/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Note: replace your Subscription ID in the above – you may also wish to deploy to multiple Subscriptions or to a Resource Group, based on your own environment.
This will provide an output that includes 4 important details – save these (and treat these as sensitive!) as you will need these later on to setup Terraform Cloud:
-
ARM_CLIENT_ID
-
ARM_CLIENT_SECRET
-
ARM_TENANT_ID
-
ARM_SUBSCRIPTION_ID
These details can now be added to Terraform Cloud – ensure that you mark these as Sensitive. You may wish to use these credentials across multiple Workspaces, and this guide explains how to configure this: Create a credentials variable set | Terraform | HashiCorp Developer.
Sample Code Repository – A simple lab you can deploy to get started!
I have created a sample repository that provides a starting point, and sets up the required elements that are required as variables within Terraform Cloud. Just to note – this is the way I am deploying, but there are other environments you could use, and different ways you can deploy. The lab I’ve shared is just a starting point that builds the following out:
-
Resource Groups
-
Virtual WAN
-
Virtual Networks and Subnets
-
Key Vault
-
Bastion
Note: this lab has since been updated and now includes more features – A blog post will be released on this soon!
All Resources are deployed within a single Subscription that is defined using the “subscription_id” variable. You will also note that a Map Variable is used to define the Azure Regions – if you require more regions, just add another variable to the Map.
Two Regions:
regions = { region1 = { region = "uksouth" code = "uks" cidr = "10.10.0.0/19" } region2 = { region = "eastus" code = "eus" cidr = "10.11.0.0/19" } }
Example – Adding another Region:
regions = { region1 = { region = "uksouth" code = "uks" cidr = "10.10.0.0/19" } region2 = { region = "eastus" code = "eus" cidr = "10.11.0.0/19" } region3 = { region = "ukwest" code = "ukw" cidr = "10.12.0.0/19" } }
A couple of Sample Lab considerations…
To get started using this environment you can connect Terraform Cloud to GitHub, without modifying the files – just clone the sample repo I have shared. However, it’s worth noting that there are two files that have additional configuration, that you may not have seen if you’ve been working locally with Terraform previously:
Provider.tf
Within the provider.tf we need to define our Subscription, Client ID and Secret, and Tenant ID – the same outputs that our Service Principal code generated above.
# Provider provider "azurerm" { subscription_id = var.subscription_id tenant_id = var.tenant_id client_id = var.client_id client_secret = var.client_secret # Provider Configuration options features { key_vault { purge_soft_delete_on_destroy = true } } }
Variables.tf
We also need to define these within the variables.tf – I choose to do this as per the below and comment out. It keeps the code neat and also means that if I need to work locally, I can do so without having to make many changes to my code:
# Service Principal variable "client_id" {} variable "client_secret" {} variable "tenant_id" {} variable "subscription_id" {} # Admin Account (For Key Vault Access Policy) variable "admin_id" {} # Naming variable "lab_name" {} # Regional variable "regions" { type = map(any) default = { region1 = { region = "uksouth" code = "uks" cidr = ["10.10.0.0/16"] } } }
You may also notice above, I have a variable defined as “admin_id” and “lab_name” – I’ve added these to cover off the below requirements:
- admin_id – This is the GUID of the account that is used to administrate the lab – so in my case this is my personal account. This is used within the code to set an access policy on the Key Vault (to ensure that the admin has access). See Line 30 below:
# Key Vault resource "random_id" "kvname" { byte_length = 5 prefix = "kv-" } data "azurerm_client_config" "current" {} resource "azurerm_key_vault" "keyvault" { name = random_id.kvname.hex resource_group_name = azurerm_resource_group.rg-sec["region1"].name location = var.regions.region1.region enabled_for_disk_encryption = true tenant_id = var.tenant_id soft_delete_retention_days = 7 purge_protection_enabled = false sku_name = "standard" access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azurerm_client_config.current.object_id key_permissions = ["Get", ] secret_permissions = ["Get", "Backup", "Delete", "List", "Purge", "Recover", "Restore", "Set", ] storage_permissions = ["Get", ] } access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = var.admin_id key_permissions = ["Get", ] secret_permissions = ["Get", "Backup", "Delete", "List", "Purge", "Recover", "Restore", "Set", ] storage_permissions = ["Get", ] } tags = { environment = "security", region = var.regions.region1.code, tfcreated = "true" } }
- lab_name – This one is more simple, and I’m just using this for naming and tagging. For example, see the Virtual WAN section below:
# Virtual WAN resource "azurerm_virtual_wan" "virtual-wan1" { name = "virtualwan-${var.lab_name}-${var.regions.region1.code}-01" resource_group_name = azurerm_resource_group.rg-con["region1"].name location = var.regions.region1.region # Configuration office365_local_breakout_category = "OptimizeAndAllow" tags = { environment = "connectivity", region = var.regions.region1.code, tfcreated = "true", lab = var.lab_name } }
✅ Once you have an Azure Subscription, Code Editor, GitHub Repository, and Service Principal, you are ready to start deploying to Azure using Terraform Cloud!
Next Steps
Now that we have all of the required elements in place – you are ready to start using Terraform Cloud. To help start, I’d recommend following the Get Started Guide from HashiCorp, and use this to deploy the sample environment that I have shared. To help guide this, for Azure deployment specifically, I would recommend working through the following articles in particular:
- Create a credentials variable set | Terraform | HashiCorp Developer – This will enable us to add our Service Principal Details to Terraform Cloud.
- Create a workspace | Terraform | HashiCorp Developer – This will enable us to create a Workspace to hold our deployment Project.
- Create infrastructure | Terraform | HashiCorp Developer – Finally, we can deploy our infrastructure using Terraform Cloud.
✅ I hope this article has been useful in providing an overview, prerequisites, Sample Lab, and Resources for Azure deployment using Terraform Cloud – until next time!
Further Reading and Additional Resources
- Deploying Terraform using GitHub Actions: https://github.com/jakewalsh90/Terraform-Azure/tree/main/GitHub-Actions-Deployment
- Sample Environments to deploy – GitHub – jakewalsh90/Terraform-Azure: Contains Terraform code for Azure deployment – snippets, useful bits, samples, labs and more. All deployable in small instances with ready to go code. Includes GitHub Actions guide to help with deployment/learning.
- Authenticate Terraform to Azure | Microsoft Learn
- Terraform on Azure documentation – Articles, samples, references, and resources – Terraform | Microsoft Learn
- Overview of Terraform on Azure – What is Terraform? | Microsoft Learn