Refactoring to move a provider from a child module from the root module

I have a legacy module that declares an aws provider inline. This is now considered poor practice. I am trying to refactor my Terraform so that the provider is declared at the root level, instead, and passed into the module.

What I have now:

root:

provider "aws" {
    region = "us-west-2"
}

module "foo" {
    source = "foo-source"
}

foo-source/provider.tf:

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

foo-source/foo.tf:

resource "aws_instance" "my_instance" {
    provider = aws.foo
    # ...
}

What I want to have:

root:

provider "aws" {
    region = "us-west-2"
}

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

module "foo" {
    source = "foo-source"
    providers = {
        aws = aws
        aws.foo = aws.foo
}

foo-source/foo.tf:

resource "aws_instance" "my_instance" {
    provider = aws.foo
    # ...
}

When I try to do this, I get:

Error: Provider configuration not present

To work with module.foo.aws_instance.my_instance its
original provider configuration at
module.foo.provider.aws.foo is required, but it has been
removed. This occurs when a provider configuration is removed while objects
created by that provider still exist in the state. Re-add the provider
configuration to destroy
module.foo.aws_instance.my_instance, after which you can
remove the provider configuration again.

Is there a way I can complete this refactor successfully without having to destroy or recreate the many resources created by the old provider? Or without having to terraform state rm and terraform import all of them?

Did you find any solution to this issue?

Hi,

I ran into the same problem that you encountered, I had a provider defined in a child module which was, as you said, considered kinda deprecated by now.

The strange thing is that I did the same thing that you did, I removed the provider from the child module and added a provider’s block into the module block in the root module, and it worked.

The only difference is I was working with the azurerm provider, and I didn’t provide an alias, I only used the provider name that was already in the root module.

root:

module "foo" {
    source = "foo-source"
    providers = {
        azurerm = azurerm
}

i also spent a couple of hours trying to find a good solution for moving resources from an explicit child module provider configuration to the parent provider configuration inheritance. Right now it seems that this is kinda the only way to do it.

I also tried using terraform state replace-provider but since you’re already using the same provider from terraform side this doesn’t seem to work…