Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing multiple provider aliases to a module in terraform 0.12.13

Tags:

terraform

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..

like image 754
Ron Jarrell Avatar asked Nov 06 '19 15:11

Ron Jarrell


People also ask

Can you use multiple providers together in Terraform?

Configuring Multiple AWS providersWe can't write two or more providers with the same name i.e. two AWS providers. If there's any such need the terraform has provided a way to do that which is to use alias argument. Note: A provider block without an alias argument is the default configuration for that provider.

How do I pass a provider in module Terraform?

Providers can be passed down to descendent modules in two ways: either implicitly through inheritance, or explicitly via the providers argument within a module block.

Is Terraform 0.12 backwards compatible?

While Terraform 0.12 does have backward compatibility with Terraform 0.11 syntax, if you have access to the module's source, it is highly recommended to upgrade the modules to 0.12 as well.

How to pass providers from one Terraform Module to another?

If your root Terraform module has child modules initialized in it then you can pass providers attribute with value as an object of different providers. Passing providers to the child module (s).

What are providers in TerraForm?

Providers are Terraform plugins that are used to interact with remote systems such as Docker, AWS, Azure… Terraform has a huge list of providers. A complete list of providers can be found here. Every root module will have at least one default provider which then will be used by all the child modules.

How to have multiple AWS providers in TerraForm?

On digging further we figured out a simple way Terraform provides us to have multiple AWS providers by creating aliases. There are multiple use cases where provider alias can be used: Creating resources in multiple AWS accounts in the same terraform module. Creating resources in resources in different regions of the same AWS account.

Why is my Terraform Module not compatible with for_each or count?

To retain the backward compatibility as much as possible, Terraform v0.13 continues to support the legacy pattern for module blocks that do not use these new features, but a module with its own provider configurations is not compatible with for_each, count, or depends_on. Terraform will produce an error if you attempt to combine these features.


3 Answers

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.

like image 119
Evan Gertis Avatar answered Oct 27 '22 16:10

Evan Gertis


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.

like image 1
NeoVance Avatar answered Oct 27 '22 17:10

NeoVance


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.

like image 1
Michael Aicher Avatar answered Oct 27 '22 18:10

Michael Aicher