Recently I have been working with Terraform Cloud to deploy Azure Environments, and in my previous post I wrote about an overview of Terraform Cloud, Prerequisites for Azure Deployment, and shared some tips and links to get started. You can read this post here.
✅ In this post I wanted to expand further by running through my own Demo/Lab Environment and covering how I deploy this using Terraform Cloud – so that others can benefit from using this environment and the benefits that Terraform Cloud brings!
Lab Overview
For this post I will be using my “Core Environment” Demo Lab – this is a simple Azure Lab that simulates a small Azure environment and can be deployed across regions of your choosing easily, using Variables. The lab can be adjusted and customised however you need – it’s designed to enable learning, development, and training etc.
For a copy of the Lab Files – please visit my GitHub repo here: https://github.com/jakewalsh90/Terraform-Azure/tree/main/Core-Environment-DemoLab-v1
This Lab environment provisions the following elements:
-
Resource Groups
-
Azure Virtual WAN – with a Firewall integrated Hub, Virtual Network Gateway, and Point to Site Gateway.
-
Azure Firewall
-
Identify VMs (For Domain Controller use if needed)
-
Azure Key Vault
-
Azure Bastion
-
Various Virtual Networks and Subnets for Lab Use.
The Lab is based on using a Map Variable to define regions – so you can deploy into a Single Region, or multiple regions as you require. Entities like Virtual WAN, and Key Vault which require a single Region to deploy into are deployed into the first region within the map variable. I’ve outlined an example of this below that includes two Regions:
# Regional Map regions = { region1 = { region = "uksouth" code = "uks" cidr = "10.10.0.0/19" } region2 = { region = "eastus" code = "eus" cidr = "10.11.0.0/19" } }
As an example, if you wanted just a single region:
# Regional Map regions = { region1 = { region = "uksouth" code = "uks" cidr = "10.10.0.0/19" } }
I’ve opted to keep things as simple as possible to make this more “lab friendly” – so all regions are based on a CIDR range which is split up using the CIDRSubnet function within Terraform. Note – any changes to ranges other than 10.x.0.0/19 will need tweaks to the function configuration, so for ease of lab use, I’d recommend sticking with 10.x.0.0/19.
Note: The Lab is setup to deploy into a single Subscription – it’s done like this as for lab usage this is a common scenario in my experience. Should you need to split this out, you can do so by using additional provider blocks with a “subscription_id” defined.
Lab Diagram
The diagram below shows the most common deployment, which is across two regions – I use this regularly to demonstrate Azure concepts and core features like Azure Virtual WAN based networking, Azure Firewall, and services like Azure Virtual Desktop. I also extensively use this environment for my own personal learning and development.
In the example below – you can see I am deploying to two Regions, with the “Primary Region” Resources being those that are always created in the first region, regardless of how many Regions are chosen:
Setting up – Pre-requisites
Getting prepped for deployment of this lab is really easy! You just need 6 things in place:
- An Azure Subscription to deploy into -obviously, we won’t get far without this!
- A Terraform Cloud Organization – follow the sign-up process here, it’s a few steps to get started: https://app.terraform.io/public/signup/account?product_intent=terraform
- A GitHub Repo – for ease of getting started, I would recommend Forking my Terraform-Azure repo, this will contain all the code you need to get started. https://github.com/jakewalsh90/Terraform-Azure
- The ID of your Administrator Account within your Azure Tenant – this is because the Key Vault is created using the Service Principal in the first access policy, so we need to create an additional policy with the administrator account, so that passwords/secrets can be accessed once the lab is created. Note – you can use a group ID here if required.
- Point to Site VPN Application Setup – You will need to follow this guide, and then take the “Application ID” from Entra ID and add this as a variable called “vpn_app_id” within Terraform Cloud. This sets up the required permissions for the VPN authentication which is based on AAD (Entra ID).
- A Service Principal – to allow Terraform Cloud to interact with Azure and create/update/destroy Azure Resources within our Subscription and Tenant. The guide below is from my previous post, but explains how to get this Service Principal setup ready for use:
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 four key details – save these (and treat these as sensitive!) as you will need these later 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! I will cover adding these details below too. 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.
Terraform Cloud – creating and deploying a Lab Environment
Creating the Lab within Terraform Cloud is simple – and has been covered extensively by HashiCorp docs. I would recommend following the below guides to create the required elements:
Step 1 – Create a workspace | Terraform | HashiCorp Developer
This will enable us to create a Workspace to hold our Lab. When creating this and following the process – you will be asked to link to a Version Control System. If you are using GitHub and have forked my Repository, set the working directory as per the below:
Step 2 – Create a credentials variable set | Terraform | HashiCorp Developer
This will enable us to add our variables. Just a note on this – be sure to mark these as sensitive, as per the below:
Once all the variables for this Lab are added, you should see a variables overview like the below. Remember that for my demo lab environment, there are 6 Variables required:
- admin_id – The GUID of the Admin User or Group you want adding to the Key Vault.
- client_id – The Client ID of the Service Principal.
- client_secret – The Client Secret of the Service Principal.
- subscription_id – The ID of the Subscription that you want to deploy into.
- tenant_id – The ID of the Tenant that you want to deploy into.
- vpn_app_id – The VPN Application ID setup in the Previous Steps (following this guide).
Note: Other guides and environments will have different variables that are required – for this lab however, you will need all six of the above!
You are now ready to create infrastructure!
Step 3 – Create infrastructure | Terraform | HashiCorp Developer
Finally, we can deploy our infrastructure using Terraform Cloud. To run the apply, click on “New Run” and then select “Plan
Your environment will then be created, and you can see the Apply phase taking place:
Once the apply has finished – you will see the following Azure Resources are in place. Note, for this blog post – I have deployed only a Single Region, which will be around 47 Resources:
Core Features of the Lab
Once you’ve deployed the lab, you’ll be able to start using it right away – in this section of my post, I wanted to explain a few key aspects in more detail!
Accessing VMs
Each Region has 2 VMs for general purpose use – as Domain Controllers or other purposes. To access these virtual machines, you will need to get the password from the Key Vault (it is a secret called “vmpassword“) – which is randomised using the Random Provider. Every single Lab deployment has a different value for this password.
The administrator account for the VMs is setup within the code section below:
os_profile { computer_name = "vm${each.value.code}ide02" admin_username = "azureadmin22" admin_password = azurerm_key_vault_secret.vmpassword.value }
The default value is “azureadmin22” – feel free to change this if you wish!
These Virtual Machines can then be accessed using the Azure Bastion instance the lab creates in each region:
Controlling Traffic with Azure Firewall
Azure Firewall is deployed within each Virtual WAN hub – and a default firewall policy called “fwpol-regioncode-1” is created. All traffic, North/South, East/West, and any VPN traffic is forced via the Hub Firewalls, so you can make this Lab as open or secure as you require. As a starting point, the lab initially has an allow everything rule in place – adjust this for your own lab as you wish:
Adjusting this within Terraform is also straightforward – and the block below shows the default rule collection group:
# Policy Rule Collection Group resource "azurerm_firewall_policy_rule_collection_group" "fwrcg1" { for_each = var.regions name = "fwrcg-${each.value.code}-01" firewall_policy_id = azurerm_firewall_policy.fwpol1[each.key].id priority = 100 network_rule_collection { name = "network_rules1" priority = 100 action = "Allow" rule { name = "network_rule_collection1_rule1" protocols = ["TCP", "UDP", "ICMP"] source_addresses = ["*"] destination_addresses = ["*"] destination_ports = ["*"] } } }
Using the Point to Site VPN
The lab also includes a Point to Site VPN configuration, providing a Gateway within each Region, and a configuration that allows users to dial in, with failover between Regions:
To dial into the Lab, you simply download the Azure VPN Client, download the configuration (above), import the configuration, and authenticate – and you’ll be dialled into the Lab environment.
Each Hub also has a VPN Gateway if a Site-to-Site connection is required:
These are just a few of the key features of the Lab – there are more, but I wanted to specifically highlight these to help get started!
Cleaning up the Lab
Lastly, but by no means least – we need to look at how to clean up the lab once completed. This is important to ensure any Azure costs are kept within budgets – especially if you are using MSDN Subscriptions or similar. To destroy the lab environment, browse to “Settings” and then “Destruction and Deletion” within your Workspace:
Then click on “Queue destroy plan” and follow the instructions:
Once the destroy plan has been conducted, you’ll be asked to confirm this. Once confirmed – the destroy will then run, and you will see a similar window to the below:
When this completes – the Terraform Destroy process will be completed, and you’ll see a message like the below:
Can you add a feature or new Service to this lab?
Yes, you can! Feel free to edit the code as you wish, or if there are features you’d like to see in this lab, please feel free to reach out – I’m happy to help create new environments that will be shared with the community, or you are welcome to use this code for your own purposes and add new elements.
Conclusion
I hope this post and supporting lab environment code has been useful – and provides a simple and easy to use Lab environment for Azure. Any questions or comments please do reach out!