Terraform resources with dynamic provider values

February 11, 2021 

Sometimes you'd like to pass a dynamic value to a Terraform resource's provider parameter. This can be done, but some background first.

Terraform allows you to define multiple providers of the same type using provider aliases. This is useful when you're working with a provider that is tied to a region, the AWS provider being a prime example. The moment you want to create resources in multiple regions you will have to learn provider aliases.

If some of your resources are in nested modules you need to pass them down from their parent module like this:

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

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

module "production" {
  source            = "../modules/cloud"
  providers         = { aws = aws,

                        aws.us-east-2 = aws.us-east-2 }
  --- snip ---

This works well until you use the same module to produce several nearly identical environments. Say "production", "staging" and "development", which are not necessarily located in the same region. At that point you may very well encounter that one pesky resource that would need to have a "provider" parameter whose value is constructed dynamically. At this point you're itching to do something like this:

resource "aws_s3_bucket" "mybucket" {
  bucket = "mybucket.example.org"
  provider = "aws.${var.s3_bucket_region}"
}

The thanks you get from Terraform in return is this:

Error: Could not load plugin
                                                                                          
Plugin reinitialization required. Please run "terraform init".

This happens because Terraform thinks you are trying to use provider type "var" which has the alias of "${var.region}". In other words it does not expect a string as the argument and gets completely confused. Apparently resource providers are evaluated before variable expansion, so you have to hardcode the provider to each resource.

Fortunately you're not totally shit out of luck. If you're motivated enough you can wrap the resources that need dynamic provider configuration into module and pass that module the correct providers as shown at the top.

Samuli Seppänen
Samuli Seppänen
Author archive
menucross-circle