Effortless Infrastructure: Crafting Custom Modules with Terraform on Azure (AKS & ACR Setup)

Ahson Shaikh
3 min readJul 15, 2024

--

If you are new to Terraform and literally have no idea about this, don’t worry, you will learn along. You just need to keep these few points in mind.

Project: Setting up AKS Cluster, NodePool, ACR, Resource Group with Terraform

  1. Provider -> AWS, Azure, GCP, Kubernetes (Browse Providers | Terraform Registry)
  2. Modules -> Reuseable Components in Terraform Configuration Files.
  3. Variables -> Reuseable Values in Terraform Configuration Files.

I do believe that learning these will simplify your terraform skills to accomplish this task.

Understanding the Terraform Hirarchy

project-root/
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfvars
├── provider.tf
├── modules/
│ ├── azure-rg/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ ├── compute/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ ├── storage/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ └── database/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
├── environments/
│ ├── dev/
│ │ ├── main.tf

This sure looks terryfying but, believe me, once you start practicing it, it is really not. So from where you should be starting? Look at the root directory. Even after describing modules, you have to call that module in the root file named “main.tf” like this:

terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.110.0"
}
}
}

provider "azurerm" {
features{
resource_group {
prevent_deletion_if_contains_resources = false
}
}
subscription_id = var.subscription_id
client_id = var.client_id
client_secret = var.client_secret
tenant_id = var.tenant_id

}

module "resource-group" {
source = "./modules/azure-rg"
resource_group_name = var.resource_group
location = var.location
tags = var.tags
}



But, how variables are being populated? Let’s look at the root variables.tf file.

variable "client_id" {}
variable "client_secret" {}
variable "subscription_id" {}
variable "tenant_id" {}

variable "resource_group" {
description = "The name of the Azure Container Registry"
type = string
default = "K8-Terraform-RG"
}


Now let’s look at the module that how it is parsing those variables to the actual resource.

This is azure-rg (main.tf)


resource "azurerm_resource_group" "aks" {
name = var.resource_group_name
location = var.location
tags = var.tags
}

variable "location" {
description = "The location for ACR"
type = string
}

variable "tags" {
description = "Tags to apply to the resources"
type = map(string)
default = {
"ProvisionedBy" = "Ahson Shaikh",
"Validity": "1d"
}
}

Now the variables used inside the module are defined in variables.tf (module)

├── modules/
│ ├── azure-rg/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf

Variables.tf

variable "resource_group_name" {
description = "The resource group name for ACR"
type = string
}


variable "location" {
description = "The location for ACR"
type = string
}

variable "tags" {
description = "Tags to apply to the resources"
type = map(string)
default = {
"ProvisionedBy" = "AhsanShaikh",
"Validity": "1d"
}
}

Variables in the module without the default values are required and the one with values is optional or can be overwritten when called in the root “main.tf” file.

The code is provided in the github link below. You just need to provide variables.tfvars these 4 values.

  subscription_id = "your-subscription-id"
tenant_id = "your-tenant-id"
client_id = "your-application-id"
client_secret = "your-client-secret"

You have to register an application in Azure Entra ID and provide it the access for owner on subscription level. Because contributor gets issues while creating the AKS.

MuhammadAhsanDonuts/terraform_infra_01 (github.com)

Thanks for reading ❤

--

--

Ahson Shaikh

DevOps Engineer with 4 years of experience in cloud and on-premises environments, specializing in Python automation with Selenium, currently working at Arpatech