Provider configuration not present - trying to destroy a module that has a required sub-module

Hello,

I’m a bit new to TF so not sure if I’m missing something obvious.

I am using a library of TF modules stored in GitHub. An AWS serviceX TF module was used to deploy an instance of serviceX. The serviceX module calls an AWS KMS TF submodule to enable encryption. KMS encryption is required by the serviceX TF module. No issues with the deployment, everything worked as expected.

The instance of serviceX was created for testing purposes, is no longer necessary and needs to be destroyed. By removing all references to instance of serviceX in the TF manifests, I encounter the below error message during plan (kms provider is defined in the submodule):

Error: Provider configuration not present

To work with module.serviceX.module.kms.anyKmsResource its original provider configuration at module.serviceX.provider.aws.kms is required but it has been removed.
Re-add the provider configuration to destroy module.serviceX.module.kms.anyKmsResource, after which you can remove the provider configuration again.

While I understand the explanation in the error message, I’m not quite sure the best way to solve the issue. The module that TF wants requires KMS so I cannot remove all the KMS related resources as a first step.

The only solution I can think of is to temporarily modify the serviceX module to not require KMS, destroy the KMS related resources as a first step, and then destroy module.serviceX as a second step.

But that seems a bit excessive, is there a better way? Is it possible to simply add a KMS provider reference at the root (based on the wording of the error message probably not)?

Thanks.

Hi @tickermcse76,

This “chicken-and-egg problem” is unfortunately the reason why we deprecated using provider blocks inside nested modules a few years ago in Terraform. We could not make it actually forbidden due to there being lots of configurations out there like yours which were already making use of it, but we recommend against this design for new modules.

With that said though, I realize that “you shouldn’t have built it this way” is not a helpful answer when this module already exists, particularly since it sounds like you are inheriting a system that someone else designed and so you probably don’t have the context for why it was built this way.

If you weren’t intending to immediately remove this module anyway then I would’ve suggested refactoring it so that the provider configuration this module uses is in the root module and passed down explicitly to the child module, and although it feels like a lot of busywork to do refactoring for a module you’re just about to remove anyway, I unfortunately don’t have any better suggestion in mind. Essentially then, I think you already identified the best answer, which is to complete just enough of a “refactor” to allow you to get this module destroyed.

If modifying the real module is inconvenient, e.g. because it’s published in some external source which you’d need to re-publish, I can at least show you a trick to replace the external module with a local module that happens to preserve the provider address:

Create a subdirectory under the module directory that contains the module "serviceX" block – for the sake of example, I’ll call it serviceX-placeholder – and put in it a single file containing the following:

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

provider "aws" {
  alias = "kms"

  # (write here the simplest possible configuration that
  # will allow you to successfully destroy everything
  # that module was managing)
}

Then change the module "serviceX" block to be just the following stub:

module "serviceX" {
  source = "./serviceX-placeholder"
}

Since Terraform is tracking the provider configuration using the module name kms, the provider source address hashicorp/aws, and the alias “kms”, the above should put a configuration at module.serviceX.provider.aws.kms, even though it’s not the one that originally created the resources.

Terraform should therefore hook the existing resources in the state up to this new stub configuration and be able to plan to destroy them, as long as the credentials in the stub configuration have sufficient access to do that.

Looking closer at your error message I’m noticing that you seem to be using an older version of Terraform that predates Terraform v0.13 and therefore doesn’t track this provider as hashicorp/aws yet, because that version doesn’t yet support auto-installing any providers other than the official ones.

If that’s true then you may need to use a reduced version of that stub configuration I shared, consisting only of the following:

provider "aws" {
  alias = "kms"

  # (write here the simplest possible configuration that
  # will allow you to successfully destroy everything
  # that module was managing)
}

Older versions of Terraform know this provider simply as “aws” rather than hashicorp/aws, so there’s not yet any need for the required_providers block which serves to declare that this module uses the local name “aws” to refer to the global name hashicorp/aws.

If you’re not yet using Terraform v0.13 or later then use this simplified configuration for now and don’t worry too much about the other details I’ve shared here… you can worry about those when you’re ready to upgrade to Terraform v0.13. :smiley:

@apparentlymart - You are correct, we are currently on v0.12.xx.

Thank you for the suggestion - it worked like a charm (using the placeholder local module trick).