Skip to content

A demonstration of provider aliasing and modular resource layout for performing coordinated work in multiple regions.

Notifications You must be signed in to change notification settings

chrismarget/multi-region-terraform-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VPC peering with terraform

This project is a demonstration of using terraform provider aliasing and modular resource layout to do work in multiple AWS regions within a single terraform project.

Specifically, we'll be creating a VPC in each of three regions, configuring VPC peering between those regions, and establish routes so that resources created in those regions can talk to one other.

Interconnected resources in three regions

The project structure looks like this:

.
├── main.tf
├── provider.tf
├── variable.tf
├── versions.tf
├── per-region
│   └── main.tf
├── vpc
│   └── main.tf
└── vpc-peering
    └── main.tf

Define multiple regions

The top-level project's provider configuration specifies multiple aws providers and creates an alias for each one.

provider "aws" {
  alias  = "us-east-1"
  region = "us-east-1"
}

provider "aws" {
  alias  = "us-east-2"
  region = "us-east-2"
}

provider "aws" {
  alias  = "ca-central-1"
  region = "ca-central-1"
}

Because of these alias directives, there is no default aws provider at the top level of the project. We'll need to specify which provider we need when when calling for any aws resource or data object at the top level.

Repeating single-region work in multiple regions

Top-level main.tf calls the per-region module three times (once for each region), and passes a different provider each time.

The per-region module doesn't directly create any resources. Rather, it exists only to call other modules: Modules which are not aware that work is being done in multiple regions, use only a default provider, and do not expect to need to pick their configuration data out of a per-region map. Y'know, regular terraform stuff.

To better understand the purpose of the per-region module, consider the contents of variable.tf:

variable "cidr" {
  default = {
    us-east-1 = "172.20.0.0/24"
    us-east-2 = "172.20.1.0/24"
    ca-central-1 = "172.20.2.0/24"
  }
}

Top-level main.tf and the per-region module know the cidr values for all three regions, but the vpc module (which doesn't know it's a clone) is expecting something more like:

variable "cidr" { default = "172.20.0.0/24" }

The per-region problem solves that problem by looking up the correct element from the cidr map and passing only that value when calling vpc:

module "vpc" {
  source = "../vpc"
  cidr = var.cidr[data.aws_region.current.name]
}

Additionally, because main.tf called per-region with only a default/un-aliased aws provider, there's no confusion about which provider to use when vpc is doing its work.

In a real project, vpc would be just one of many single-region modules called by per-region. The per-region module isn't strictly required (main.tf could call vpc directly with the correct variables), but as modules and resources bloom, things get crowded fast, and I find the per-region abstraction helpful.

Coordinating work across multiple regions

Top-level main.tf also calls the vpc-peering module. Like the vpc module, it also winds up getting called three times. vpc-peering differs in that it knows about multiple providers/regions because creating a VPC peering connection requires doing coordinated work on both ends of the connection (in different regions). It does not need to be "protected" from this information by an intermediate module.

Calling the vpc-peering looks like:

module "peering_1" {
  source = "./vpc-peering"
  accepting_vpc_id = module.us_east_2.vpc_id
  requesting_vpc_id = module.us_east_1.vpc_id
  providers = {
    aws = aws.us-east-2                   # Default aws provider for module
    aws.requesting = aws.us-east-1        # Named/aliased provider for module
  }
}

Note that we're passing two providers to the module this time. Like before, one provider serves as the aws default, but the second one is aliased aws.requesting, and will need to be explicitly referenced when used within the module. There is no requirement to pass a default provider. Aliasing both would have worked as well. But aliasing only a single module saves some typing in the data and resource stanzas within the module.

About

A demonstration of provider aliasing and modular resource layout for performing coordinated work in multiple regions.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages