DEV Community

Cover image for Creating a shared configuration module in Terraform
Denis Cooper
Denis Cooper

Posted on • Originally published at deniscooper.co.uk

Creating a shared configuration module in Terraform

💭 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"
  }
}

Enter fullscreen mode Exit fullscreen mode

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"]
  }
}

Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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]
}
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
grantwakes profile image
Grant Wakes

Really like this pattern of a shared config module as a single source of truth for region/env values. Using outputs plus locals for lookups is a clean way to kill duplication and config drift. Simple approach, but very effective in larger Terraform codebases.