Creating Resource Groups In Azure Using Terraform

Introduction 

 
Terraform has been the buzzword for a while when it comes to Infrastructure as a Code (IaC) deployments for multiple cloud providers. Recently, we got a chance to work on an enterprise set up for Terraform from the ground up and build multiple orchestrations for resource deployment or management in Microsoft Azure. During this journey, we encountered a lot of issues, figured out multiple shortfalls, and how to work around the shortfalls to achieve the desired results. We are trying to share the knowledge for some of the use cases and items that we feel can be reused across multiple engagements and will also save time for individuals to figure things out.
 
Creating Resource Groups In Azure Using Terraform
 
Kicking off this series with one of the easier implementations for creating a new Azure Resource Group using Terraform. The reusable code for this particular use case is available at create-resource-group. Note that all code is written for Terraform 0.12.x
 
Pre-Requisites
  • Client ID/Secret or System Assigned Managed Identity for Terraform to use
  • Subscription ID: This is the target Azure subscription for deployment
  • Tenant ID: This is the target Azure Tenant
In this version of code, we are passing these values via the Terraform variables. We will share a subsequent version where we will fetch these details from the Azure Key Vault.
 
The code hierarchy that we are going to follow over all our subsequent blogs will be as depicted below. Each deployment type has a separate folder containing all required files including the main file, a variables file, an output file, and an optional .tfvars file that provides inputs for executions.
 
Creating Resource Groups In Azure Using Terraform
 
The first order of action is to define the Terraform provider for Azure. We need to specify the version and features as mandatory parameters in this block in the newer version of Terraform. We are also providing the information that Terraform needs for authenticating and performing the requested action in Azure by including target subscription id, Azure tenant ID and Azure client ID and secret. In case you have System Assigned Managed Identity available to be used in your enterprise setup, uncomment the use_msi attribute and comment the client id and secret.
  1. provider "azurerm" {  
  2.     version = ">=2.4.0"  
  3.     subscription_id =  
  4.         var.subscription_id  
  5.     tenant_id =  
  6.         var.tenant_id  
  7.     //For Service Principle based authentication  
  8.     client_id =  
  9.         var.client_id  
  10.     client_secret =  
  11.         var.client_secret  
  12.     //use_msi = true // set to true for using System Assigned Managed Identities  
  13.     features {}  
  14. }  
The locals block is used to perform manipulations with the variables. In this case, we are just working around a couple of limitations for resource group names — 1) 64 character limit set by Azure and 2) Space in resource group name not accepted by Terraform. Essentially, this is the block that we will use to define any standardizations like naming conventions or any other calculations/manipulations with variables to be used for provisioning.
  1. locals {  
  2.     // 1. We are doing a replace on spaces in resource group name since Terraform is not supporting that currently  
  3.     // 2. We are also truncating the rg name if it is greater than 64 characters since that is the max that Azure supports  
  4.     rg_name = replace((length(var.resource_group_name) > 64 ? substr(var.resource_group_name, 0, 63) : var.resource_group_name), " ""-")  
  5. }  
The resource block is the part of the Terraform code that will actually be responsible for doing the intended deployment. Each resource will have a module and a name. Within the resource block, we will specify the attributes for a resource to be configured. In this case, the module is “azurerm_resource_group” and the name is “rg”. We are specifying the attributes for name, location, and tags for the resource group.
  1. resource "azurerm_resource_group"  
  2. "rg" {  
  3.     name = local.rg_name  
  4.     location =  
  5.         var.resource_location  
  6.     tags = {  
  7.         InstanceType =  
  8.         var.instance_type  
  9.     }  
  10. }  
For getting the output of this particular resource, we need to add the following in the output.tf file.
  1. output "ResourceGroupId" {  
  2.     description = "id of the resource group provisioned"  
  3.     value = "${azurerm_resource_group.rg.id}"  
  4. }  
  5. output "ResourceGroupName" {  
  6.     description = "name of the resource group provisioned"  
  7.     value = "${azurerm_resource_group.rg.name}"  
  8. }  
That’s It! We are ready with the code and now we just need to perform Terraform Init before doing a Terraform plan. Once the Terraform plan is successful, you can do a Terraform apply and the resource will be provisioned.
  1. terraform plan -var-file="<yourfilename>.tfvars" or terraform plan  
  2. terraform apply -var-file="<yourfilename>.tfvars or terraform apply  
We have gotten into details of each section in this article since this is the beginning and basis understanding of each block is quite important to understand and implement complex use cases. This should get you started with sufficient details on your Infrastructure as Code with Terraform.
 
You can explore more documentation on the Terraform site and MSDN as well for some basic information. We will continue to develop on the understanding one use case at a time to tie together the information with hands-on implementations and challenges.
 
Happy Coding!