Choosing different provider at runtime

I am looking for how to select which aws provider to use for all resources (modules, resources, etc)… at runtime.
I am configuring multiple aws providers in my tf file but during a run I want select which gets used.

Basically I’ve seen examples of selecting between providers on the resource level so you can create a bucket in accountA and another in accountB

What I’m trying to do is create a complete stack in accountA OR accountB OR accountZ

so therefore the entire stack would need to run with an alternative provider.

I looked for a --provider flag for the plan/apply runtime but don’t see an option.

Anyone have an example that will work for all child modules and resources?

To use a different provider, you must edit the Terraform source files accordingly.

There is no accomodation for selecting a provider to use based on runtime flags.

So in order to run in CI which would run as particular role for current account. I’d need to modify the source to put in assume_role to that provider? Is there anyway I can move the provider to a -var-file? Or something similar so the code can stay intact? Each cluster I could use it’s own var-file which could contain the correct provider statement (but var-files aren’t HCL) Just seems weird you can’t modify at runtime with a variable or something to switch the default provider.

I’m trying to avoid having to duplicate code in order to do this if possible.

I suspect multiple provider blocks with alias could work.

Each relevant resource would need the alias directive to use the appropriate provider block.

@cdenneen You can define just one provider whose configuration is expressed in terms of variables, and set those variables via -var-file.

@shantanugadgil No, provider aliases are not the answer, because you still can’t select which aliased provider your resources are using without editing the code.

The alternate providers need an assume role not sure I can do for a conditional if account B or Z but with default I don’t need to assume role so that block wouldn’t be necessary.

Unless I can have the default assume itself not sure if that would work then the assume role could be a VAR.

I do not have experience doing this, but it is possible that dynamic block syntax (Dynamic Blocks - Configuration Language | Terraform | HashiCorp Developer) could be used to conditionally define zero or one assume_role block.

Alternatively, perhaps one of the other authentication configuration sources, that doesn’t involve having anything in the Terraform file at all, could be used (Terraform Registry)

One of the Terraform configurations we use internally is normally used with AssumeRole but has a special “bootstrapping” mode where we use direct credentials in order to initially create the role that will be assumed for routine work.

Here’s one of the provider configurations from that, showing one way to dynamically configure assume_role:

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

  region              = "us-east-1"
  allowed_account_ids = [local.aws_account_id]

  dynamic "assume_role" {
    for_each = local.assume_role_arn[*]
    content {
      role_arn    = assume_role.value
      external_id = "us-east-1"

local.assume_role_arn is null when in bootstrapping mode and set to a non-null string containing an ARN when not in bootstrapping mode.

In our case the non-null assume role ARN is taken from a role declared elsewhere in the same module, but the same strategy should work if you have an input variable that is nullable and set to null in situations where assume_role isn’t needed.