immutableT
immutableT

Reputation: 469

How to deploy AWS resources across all regions via terraform?

I need to deploy AWS GuardDuty across all accounts/regions in my AWS Organization. My first step is to delegate GuardDuty's administration to a designated account. Since, GuardDuty is a regional resource, I need to perform such delegation across all regions. Note that we are operating in pretty much every region of AWS.

Here is a brute-force approach for accomplishing this task:

provider "aws" {
  region  = "us-east-1"
  alias   = "us-east-1"
}
provider "aws" {
  region  = "us-east-2"
  alias   = "us-east-2"
}
# Do the same for the remaining regions

resource "aws_guardduty_organization_admin_account" "us-east-1" {
   provider = aws.us-east-1
   admin_account_id = "123456789..."
}
resource "aws_guardduty_organization_admin_account" "us-east-2" {
 provider = aws.us-east-2
 admin_account_id = "123456789..."
}

# Do the same for the remaining regions

This works, but has several disadvantages:

Question: Is there a better way of doing this? There is an old thread on this scenario here: https://github.com/hashicorp/terraform/issues/451

However, it does not appear that a good options existed at that time, so I want to see if better options are available now.

Ideally, I want to leverage data "aws_regions" "all" {} to loop over the existing regions and dynamically create the delegation resources and providers.

I tried the approach suggested by @Matt Schuchard:

Given this resource:

resource "aws_guardduty_organization_admin_account" "us-east-1" {
  # interpolate in for expression here since not allowed in provider argument
  for_each = toset([for region in data.aws_regions.this.names : "aws.${region}"])

  provider         = each.value
  admin_account_id = "123456789..."
}

Terraform 1.0.10, produces the following error:

Error: Failed to query available provider packages
Could not retrieve the list of available versions for provider hashicorp/each: ...

Upvotes: 4

Views: 2647

Answers (1)

Matthew Schuchard
Matthew Schuchard

Reputation: 28854

You would need the for_each meta-argument for both the provider and the resource blocks to iterate over all AWS regions within a single block. If one attempts to use the for_each meta-argument with the provider block, then the error message displays:

The provider argument name "for_each" is reserved for use by Terraform in a future version.

and this is on the roadmap for future development.

However, one can do this with the for_each meta-argument in the resource block. First, you suggested retrieving all available regions with the data aws_regions to always truly target all regions:

data "aws_regions" "this" {}

where the all_regions and filters arguments can down-select the desired regions. The exported resource attribute names of type list(string) would store the desired regions.

Assuming you are configuring providers and their aliases as described in the question, you would then use this list within the resource block:

resource "aws_guardduty_organization_admin_account" "us-east-1" {
  # interpolate in for expression here since not allowed in provider argument
  for_each = toset([for region in data.aws_regions.this.names : "aws.${region}"])

  provider         = each.value
  admin_account_id = "123456789..."
}

and this would manage the resource in all desired AWS regions.

Upvotes: 2

Related Questions