Dynamic providers inside modules

Hey there.

We have an issue with dynamic providers inside modules and I am searching for a better of our implementation. Solution works, but the problem happens when we want to delete a module.

Related topics:

What we are doing?

With described Terraform solution, we are able to define a new Serverless project, for which we then setup resources in multiple AWS accounts.

How does it look like?

Because we need to setup resources in multiple AWS accounts for each project, our project structure looks like this.

  • root
    • project_aws module
      • stage module

Before you continue, please keep in mind that code below has been completely simplified.

In root, we define a list of projects in a projects.tf file, and one of the blocks/modules looks like this:

module "example-project" {
  name               = "example-project"
  source             = "./project_aws"

  stages = {
    "dev"  = "account-dev",
    "prod" = "account-prod",
  }
}

Then, in project_aws we separate this into two new modules, one for dev and one for prod, which basically looks like below. Here you can see that account_role_arn_dev and account_role_arn_prod are dynamically assigned and sent to stage module.

locals {
  account_role_arns = {
    "account-dev"  = "role_arn"
    "account-prod" = "role_arn"
    "account-temp" = "role_arn"
  }

  account_role_arn_dev  = contains(keys(var.stages), "dev") ? local.account_role_arns[var.stages["dev"]] : ""
  account_role_arn_prod = contains(keys(var.stages), "prod") ? local.account_role_arns[var.stages["prod"]] : ""
}

module "prod" {
  source              = "./stage"
  name                = var.name
  stage               = "prod"
  enabled             = contains(keys(var.stages), "prod") ? true : false
  account_role_arn    = local.account_role_arn_prod
}

module "dev" {
  source              = "./stage"
  name                = var.name
  stage               = "dev"
  enabled             = contains(keys(var.stages), "dev") ? true : false
  account_role_arn    = local.account_role_arn_dev
}

In stage module, we dynamically initiate provider (based on account_role_arn) and create all the needed resources with this provider:

provider "aws" {
  region = "eu-west-1"

  assume_role {
    role_arn = var.account_role_arn
  }
}

Once again, where is the problem?

As mentioned at the beginning, this works, but problem appears when we want to remove module/project from the root. In that case we receive a Error: Provider configuration not present which happens because we use dynamic providers and module is not able to detect which provider to use for destroying resources.

We want to put providers in root, but we also need them to be dynamic, we want to providers with alias from the root inside a module, but that is not doable.

Anyway - is there any other implementation that you suggest?

We wanted to have it more dynamically and avoid repeating the code, but we were not aware it will bring this kind of complications :slight_smile:

Thanks in advance.