Terraform: Apply config for all AWS regions

Created on 21 Dec 2017  路  9Comments  路  Source: hashicorp/terraform

Terraform Version

v0.11.1

Terraform Configuration Files

variable "regions" {
  default = [
    "us-east-1",
    "us-east-2",
    "us-west-1",
    "us-west-2",
    "ca-central-1",
    "eu-central-1",
    "eu-west-1",
    "eu-west-2",
    "eu-west-3",
    "ap-northeast-1",
    "ap-northeast-2",
    "ap-southeast-1",
    "ap-southeast-2",
    "ap-south-1",
    "sa-east-1"
  ]
}

provider "aws" {
  count = "${length(var.regions)}"
  alias = "${element(var.regions, count.index)}"
  region = "${element(var.regions, count.index)}"
  profile = "defualt"
}

resource "aws_security_group" "http-https" {
  count = "${length(var.regions)}"
  provider = "aws.${element(var.regions, count.index)}"
  name = "http-https"
  ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Expected Behavior

Creating a security group on each AWS regions.

Actual Behavior

Planning/Applying fails with

Error: Error asking for user input: 1 error(s) occurred:

* aws_security_group.http-https: configuration for aws.${element(var.regions, count.index)} is not present; a provider configuration block is required for all operations

Steps to Reproduce

  1. terraform init
  2. terraform apply
config enhancement

Most helpful comment

In Terraform v0.12.0 we've reserved the variable name provider so that in a future release module blocks can contain instance-specific provider configurations when using for_each or count:

module "regional" {
  source   = "./modules/regional"
  for_each = var.regions

  provider "aws" {
    region = each.value
  }
}

The above is intended to mean that within that module the default (unaliased) aws provider configuration is set to the one declared inside this block, thus allowing it to incorporate values from each. (If count were being used then that could be count.index instead.)

A design challenge with this is that it causes the same problem as having the provider declaration within the module itself: if you delete the module block then Terraform needs to delete all of the resources it was managing but no longer has the provider configuration that created them.

Therefore we need to do some more design iteration to figure out a suitable design here. The problem could potentially be avoided by allowing for_each on provider configurations themselves, but Terraform's internal handling of providers will need to be significantly reworked for that to be possible:

provider "aws" {
  for_each = var.regions

  region = each.value
}

module "regional" {
  source   = "./modules/regional"
  for_each = var.regions

  providers = {
    aws = aws[each.value]
  }
}

We already have some quite significant refactoring to do in order to support count and for_each on modules, so I expect we'll attack that problem first and while we are working on it look for opportunities to do foundational work for multi-instance provider configurations too. Aside from the complexity of the internal changes required, there is also the unfortunate UX oddity of having both provider aliases and multi-instance providers at the same time, so I think we'll probably also look for whether those two concepts can be combined somehow, because their interactions are likely to be confusing otherwise.


The discussion in #21612 is somewhat related to this, in that it is discussing whether region being a provider-wide setting in the AWS provider is actually a good idea anyway, and what it might do instead.

All 9 comments

Hi @dsegurag,

The count field isn't supported for providers, and interpolation is not supported in the alias field (provider interpolation). That should probably fail validation earlier, rather than continue on with a provider named aws.${element(var.regions, count.index)}.

Once we can support count on modules, that might be a good way to do something like this in the future. We can review whether having count on providers, or configuring them through modules makes more sense once we have the new configuration infrastructure in place.

@jbardin Is there any timeline for adding count to modules? It would solve some of the similar problems that we're experiencing.

Just for reference, a potential use case 馃槃 : https://github.com/terraform-providers/terraform-provider-aws/issues/3763

@jbardin do you have any new input on this? What's the supposed way to do this, modules or providers? Any ideas if it'll work with 0.12?

+1 on this. Right now I have a module that wants to create a ACM Certificate in each region that we have defined in a list of regions. Instead of having to manually add alias providers for every region, this could allow us to easily scale up a region instead of needing to have these added to the module first.

In Terraform v0.12.0 we've reserved the variable name provider so that in a future release module blocks can contain instance-specific provider configurations when using for_each or count:

module "regional" {
  source   = "./modules/regional"
  for_each = var.regions

  provider "aws" {
    region = each.value
  }
}

The above is intended to mean that within that module the default (unaliased) aws provider configuration is set to the one declared inside this block, thus allowing it to incorporate values from each. (If count were being used then that could be count.index instead.)

A design challenge with this is that it causes the same problem as having the provider declaration within the module itself: if you delete the module block then Terraform needs to delete all of the resources it was managing but no longer has the provider configuration that created them.

Therefore we need to do some more design iteration to figure out a suitable design here. The problem could potentially be avoided by allowing for_each on provider configurations themselves, but Terraform's internal handling of providers will need to be significantly reworked for that to be possible:

provider "aws" {
  for_each = var.regions

  region = each.value
}

module "regional" {
  source   = "./modules/regional"
  for_each = var.regions

  providers = {
    aws = aws[each.value]
  }
}

We already have some quite significant refactoring to do in order to support count and for_each on modules, so I expect we'll attack that problem first and while we are working on it look for opportunities to do foundational work for multi-instance provider configurations too. Aside from the complexity of the internal changes required, there is also the unfortunate UX oddity of having both provider aliases and multi-instance providers at the same time, so I think we'll probably also look for whether those two concepts can be combined somehow, because their interactions are likely to be confusing otherwise.


The discussion in #21612 is somewhat related to this, in that it is discussing whether region being a provider-wide setting in the AWS provider is actually a good idea anyway, and what it might do instead.

@apparentlymart are there any plans to introduce this feature in terraform 0.12.x?

+1 to this as I would like to create a CloudWatch Log Group for my implementation in all available AWS Regions.

Another use case: Setting up standardized AWS Config compliance rules and Cloudwatch Alarms across multiple regions.

Was this page helpful?
0 / 5 - 0 ratings