'Passing multiple provider aliases to a module in terraform 0.12.13

I'm building code that needs to talk to two different AWS accounts, which the documentation says should work. This worked under 0.11.14

In the main, in my providers.tf file I have:

provider "aws" {
  alias = "ca-central-1"
  region = "ca-central-1"
  profile = var.aws_profile
}

provider "aws" {
   alias = "other-ca-central-1"
   region = "ca-central-1"
   profile = var.aws_other_profile
}

(Those variables are set the correct profiles in my credentials file.)

In the root, in the code that calls the module,

module "obfuscated" {
  source = "./modules/obfuscated"
  providers = {
    aws.main = "aws.ca-central-1"
    aws.other = "aws.other-ca-central-1"
  }
  #other stuff
}

In ./modules/obfuscated/main.tf I have

provider "aws" {
  alias = "main"
}
provider "aws" {
  alias = "other"
}

Which the docs say is a placeholder, which can only be empty or have an alias. Without it, it complains the provider doesn't exist. But with it, it complains I didn't specify the region, which conflicts with the docs.

Surely the documentation couldn't be wrong, no, that couldn't be possible.. Help me obi-wan-overflow..



Solution 1:[1]

Here is an example of how I am handling the issue

#af-south-1
data aws_vpcs af-south-1 {
    provider = aws.af-south-1
}

module af-south-1 {
    source = "./modules/flow_log"
    providers = {
        aws = aws.af-south-1
    }
    iam_role_arn = aws_iam_role.vpc_flow_log.arn
    log_destination = aws_s3_bucket.vpc_flow_log.arn
    log_destination_type = "s3"
    traffic_type = "REJECT"
    aws_vpc_ids = data.aws_vpcs.af-south-1.ids
    depends_on = [ aws_s3_bucket.vpc_flow_log ]
}

#ap-east-1
data aws_vpcs ap-east-1 {
    provider = aws.ap-east-1
}

module ap-east-1 {
    source = "./modules/flow_log"
    providers = {
        aws = aws.ap-east-1
    }
    iam_role_arn = aws_iam_role.vpc_flow_log.arn
    log_destination = aws_s3_bucket.vpc_flow_log.arn
    log_destination_type = "s3"
    traffic_type = "REJECT"
    depends_on = [ aws_s3_bucket.vpc_flow_log ]
    aws_vpc_ids = data.aws_vpcs.ap-east-1.ids
}

#ap-northeast-1
data aws_vpcs ap-northeast-1 {
    provider = aws.ap-northeast-1
}
....

In this example I am creating a datasource aws_vpcs for each provider region. Then I pass the list of ids for each region into the module. At this time you must specify the provider for the module to use unless you are using the default provider.

Solution 2:[2]

The main problem may be that you are attempting to pass the providers values as strings rather than references to the actual provider. "aws.<alias>" vs aws.<alias>

I could be wrong, but I think you will need to include required_providers in your module terraform block.

terraform {
    required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = ">= 2.7.0"
        }
    }
}

Then you may use an empty provider or one with alias to declare the provider as a required item to be passed in the modules providers configuration.

Solution 3:[3]

The solution provided by @NeoVance is almost solving it. Indeed, the required_providers block is required in the module, but it requires the so called configuration_aliases, additionally.

terraform {
    required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = ">= 2.7.0"
            configuration_aliases = [ aws.main, aws.other ]
        }
    }
}

Here your can find the related documentation about Passing Providers Explicitely.

Solution 4:[4]

I faced the same kind of issue but for assuming a role. So in my case, I provide the role arn to use. In the module directory, for example my_module, I have a tf file with the provider. Inside the block provider, I have this:

variable "role_arn" {}

provider "aws" {
  alias   = "first"
  region  = "eu-west-1"
  version = "2.24.0"

  assume_role {
    role_arn = "${var.role_arn}"
  }
}

In a tf file within my_module directory, using the provider for creating an EC2 instance for example, I have this:

resource "aws_instance" "my_instance" {
  [...]
  provider = "aws.first"
}

And in the root directory of my project, I have this:

module "using_my_module" {
  source = "modules/my_module"

  role_arn = "arn:aws:iam::123456789012:role/role_to_assume"
}

I admit it is a technical workaround so it might look ugly but it worked for me!

I hope it would help you!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Evan Gertis
Solution 2 NeoVance
Solution 3 Michael Aicher
Solution 4