Stop Repeating Code: Shared Terraform Config Module

The Problem

I found myself committing a cardinal sin in Terraform — repeating configuration across multiple projects.

When deploying Azure resources, we often need region- or environment-specific values. For example, virtual networks may need different routes or DNS servers depending on the location.

I was managing these using lookup tables in local variables, like this:

locals {
  firewall_ip = {
    "westeurope" = "10.0.0.1"
    "northeurope" = "10.0.0.2"
  }
}

This worked fine… until it didn’t.

Every time a region or IP changed, I had to update the same table in multiple projects — a maintenance nightmare.


💡 The Realisation

What I really needed was a global lookup table — a shared, central source of truth I could query across all Terraform projects.

The solution turned out to be beautifully simple:

✅ A centralised shared configuration Terraform module.


🧱 The Shared Configuration Module

All my Terraform modules live in Azure DevOps Git Repos, so I can reference them directly rather than duplicating code.

My shared configuration module only needs one file — outputs.tf — that defines all the shared values:

output "firewall_ips" {
  description = "Firewall IP Addresses By Region"
  value = {
	prod = {
		"westeurope"    = "10.27.0.4"
		"centralus"     = "10.28.0.4"
		"australiaeast" = "10.29.0.4"
	}
	dev {
		"westeurope"    = "10.27.1.4"
		"centralus"     = "10.28.1.4"
		"australiaeast" = "10.29.1.4"
	}
`
  }
}

output "dns_servers" {
  description = "DNS Servers by Regions"
  value = {
	"westeurope"    = ["10.27.1.1", "10.27.1.2"]
	"centralus"     = ["10.28.1.1", "10.28.1.2"]
	"australiaeast" = ["10.29.1.1", "10.29.1.2"]
  }
}

This module simply outputs all the shared configuration values I want to reference elsewhere.

🪄 Calling the module

In any Terraform project, I reference it like so:

module "shared_configuration" 
  source = "gitssh://git@ssh.dev.azure.com/v3/example/Terraform-Modules/tf_module_shared_configuration"
}

Then I use a locals.tf file to do my lookups:


locals {
  # Get region-specific values from the shared module 
  firewall-ip = module.shared_configuration.firewall_ips[var.environment][var.location]
  dns-servers = module.shared_configuration.dns_servers[var.location]
}

Here’s what’s happening:

•	firewall_ip dynamically selects the right address for the target environment and region.
•	dns_servers fetches region-specific DNS values.

Whenever I reference local.firewall_ip or local.dns_servers in my Terraform code, I’m automatically pulling the correct config for that deployment.


🔁 The Benefit

Now, when I need to add a region or update a value, I just modify the shared module once.

All projects referencing it get the change instantly.

  • No duplication.
  • No missed updates.
  • No drift between environments.

⚙️ Summary

By creating a shared configuration Terraform module, you can:

✅ Keep environment and region settings consistent

✅ Avoid copy/paste duplication

✅ Simplify maintenance and updates

✅ Scale your Terraform codebase cleanly

Sometimes the best solutions are the simplest ones — we just need to stop and think about the problem first.

📖 Further Reading

Check out the Terraform Module Documentation here https://developer.hashicorp.com/terraform/language/modules

Your subscription could not be saved. Please try again.
Your subscription to deniscooper.co.uk has been successful.

Join Cloud Engineers Who Build Smarter on Azure

Free checklists, practical guides and the latest posts — built for cloud engineers working with Azure and Terraform.

Leave a Comment