'Error: Module is incompatible with count, for_each, and depends_on' and 'Error: Invalid provider configuration' errors

Hi All,

I got this error after running ‘terrafor plan’. I am using terraform v1.2.1 on Windows x64.

D:\AWS_LZ\abc-prod-shared-services\lz-sharedservices>terraform plan
╷
│ Error: Module is incompatible with count, for_each, and depends_on
│
│   on vpc-endpoints.tf line 7, in module "vpc_endpoints":
│    7:   count                     = length(var.vpc_endpoint_services)
│
│ The module at module.vpc_endpoints is a legacy module which contains its own local provider configurations, and so calls to it may not use the count,
│ for_each, or depends_on arguments.
│
│ If you also control the module "../lz-tf-modules/vpc-endpoint", consider updating this module to instead expect provider configurations to be passed by its
│ caller.
╵
╷
│ Error: Module is incompatible with count, for_each, and depends_on
│
│   on vpc-endpoints.tf line 26, in module "s3_vpc_endpoint":
│   26:   count                     = var.enable_s3_vpc_interface_endpoint ? 1 : 0
│
│ The module at module.s3_vpc_endpoint is a legacy module which contains its own local provider configurations, and so calls to it may not use the count,
│ for_each, or depends_on arguments.
│
│ If you also control the module "../lz-tf-modules/vpc-endpoint", consider updating this module to instead expect provider configurations to be passed by its
│ caller.
╵
provider.tf (In the root modules - abc-prod-shared-services folder )
=================

D:\AWS_LZ\abc-prod-shared-services>type provider.tf

# Provider for Shared Services
provider "aws" {
  region = var.region_name
  alias  = "sharedservices"
  default_tags {
    tags = var.tags
  }
}


#Provider for Network Account
provider "aws" {
  region              = var.region_name
  alias               = "networking"
  shared_config_files = ["./config"]
  profile             = "AWSAFTExecution"
  assume_role {
    role_arn = "arn:aws:iam::${data.aws_ssm_parameter.network_acc_number.value}:role/AWSAFTExecution"
  }
  default_tags {
    tags = var.tags
  }
}

terraform {

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }

  backend "s3" {
    bucket         = "abc-prod-ss-infra-aft-tfstate-ap-northeast-1-008012345678"
    key            = "02-shared-services/terraform.tfstate"
    region         = "ap-northeast-1"
    dynamodb_table = "abc-prod-ss-infra-aft-tf-state-lock"
    encrypt        = true
  }
}
vpc-endpoints.tf (In the root modules - abc-prod-shared-services )
====================

D:\AWS_LZ\abc-prod-shared-services>type vpc-endpoints.tf

module "vpc_endpoints" {
  count                     = length(var.vpc_endpoint_services)
  source                    = "../lz-tf-modules/vpc-endpoint/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = var.vpc_endpoint_services[count.index]
  master_prefix             = var.master_prefix
  vpc_tags = var.vpc_tags

       providers = {
     aws = aws.sharedservices
   }

}


module "s3_vpc_endpoint" {
  count                     = var.enable_s3_vpc_interface_endpoint ? 1 : 0
  source                    = "../lz-tf-modules/vpc-endpoint/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = "s3"
  master_prefix             = var.master_prefix
  vpc_tags = var.vpc_tags

      providers = {
     aws = aws.sharedservices
   }

}

provider.tf (In the child module folder - lz-tf-modules\vpc-endpoint )
===============================================

D:\AWS_LZ\abc-prod-shared-services\lz-tf-modules\vpc-endpoint>dir
 Volume in drive D is UserProfile
 Volume Serial Number is B408-A885

 Directory of D:\AWS_LZ\abc-prod-shared-services\lz-tf-modules\vpc-endpoint

04/17/2023  06:19 AM    <DIR>          .
04/17/2023  06:19 AM    <DIR>          ..
04/17/2023  06:12 AM             3,095 main.tf
04/13/2023  09:28 AM               388 outputs.tf
04/13/2023  09:54 PM               577 provider.tf
04/13/2023  09:28 AM             1,942 README.md
04/13/2023  09:28 AM               970 variables.tf
               5 File(s)          6,972 bytes
               2 Dir(s)  41,500,389,376 bytes free


D:\AWS_LZ\abc-prod-shared-services\lz-tf-modules\vpc-endpoint>type provider.tf

provider.tf
====================

# Provider for Shared Services
provider "aws" {
  region = var.region_name
  alias  = "sharedservices"
}

#Provider for Network Account
provider "aws" {
  region              = var.region_name
  alias               = "networking"
  shared_config_files = ["./config"]
  profile             = "AWSAFTExecution"
  assume_role {
    role_arn = "arn:aws:iam::${data.aws_ssm_parameter.network_acc_number.value}:role/AWSAFTExecution"
  }
}

terraform {

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }

}

After which I tried to comment the providers lines in the vpc-endpoints.tf, but got this error instead. Could anyone point out what is wrong with the code? Thanks.

╷
│ Error: Invalid provider configuration
│
│ Provider "registry.terraform.io/hashicorp/aws" requires explicit configuration. Add a provider block to the root module and configure the provider's required
│ arguments as described in the provider documentation.
│
╵
╷
│ Error: configuring Terraform AWS Provider: validating provider credentials: retrieving caller identity from STS: operation error STS: GetCallerIdentity, failed to resolve service endpoint, an AWS region is required, but was not found
│
│   with provider["registry.terraform.io/hashicorp/aws"],
│   on <empty> line 0:
│   (source code not available)
│


provider.tf (In the root modules - abc-prod-shared-services )
=================

# Provider for Shared Services
provider "aws" {
  region = var.region_name
  alias  = "sharedservices"
  default_tags {
    tags = var.tags
  }
}

provider "aws" {
  region              = var.region_name
  alias               = "networking"
  shared_config_files = ["./config"]
  profile             = "AWSAFTExecution"
  assume_role {
    role_arn = "arn:aws:iam::${data.aws_ssm_parameter.network_acc_number.value}:role/AWSAFTExecution"
  }
  default_tags {
    tags = var.tags
  }
}

terraform {

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }

  backend "s3" {
    bucket         = "abc-prod-ss-infra-aft-tfstate-ap-northeast-1-008012345678"
    key            = "02-shared-services/terraform.tfstate"
    region         = "ap-northeast-1"
    dynamodb_table = "abc-prod-ss-infra-aft-tf-state-lock"
    encrypt        = true
  }
}


vpc-endpoints.tf (In the root modules - abc-prod-shared-services )
===================

module "vpc_endpoints" {
  count                     = length(var.vpc_endpoint_services)
  source                    = "../lz-tf-modules/vpc-endpoint/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = var.vpc_endpoint_services[count.index]
  master_prefix             = var.master_prefix
  vpc_tags = var.vpc_tags

 #       providers = {
 #     aws = aws.sharedservices
 #   }

}

module "s3_vpc_endpoint" {
  count                     = var.enable_s3_vpc_interface_endpoint ? 1 : 0
  source                    = "../lz-tf-modules/vpc-endpoint/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = "s3"
  master_prefix             = var.master_prefix
  vpc_tags = var.vpc_tags

 #      providers = {
 #     aws = aws.sharedservices
 #   }

}


*** provider.tf removed from child module folder ***

D:\AWS_LZ\abc-prod-shared-services\lz-tf-modules\vpc-endpoint>dir

 Directory of D:\AWS_LZ\abc-prod-shared-services\lz-tf-modules\vpc-endpoint

04/17/2023  06:09 AM    <DIR>          .
04/17/2023  06:09 AM    <DIR>          ..
04/17/2023  06:12 AM             3,095 main.tf
04/13/2023  09:28 AM               388 outputs.tf
04/13/2023  09:28 AM             1,942 README.md
04/13/2023  09:28 AM               970 variables.tf
               4 File(s)          6,395 bytes
               2 Dir(s)  41,500,405,760 bytes free



main.tf in child module folder
========

data "aws_region" "current" {}

resource "aws_security_group" "vpc_endpoint_sec_group" {
  name        = format("%s-%s-%s-vpc-endpoint-%s", var.master_prefix, var.env_prefix, var.app_prefix, var.vpc_endpoint_service_name)
  description = format("Security Group for VPC Endpoint com.amazonaws.%s.%s", data.aws_region.current.name, var.vpc_endpoint_service_name)
  vpc_id      = var.vpc_id

  egress {
    description = "Outbound to vpc endpoints"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.29.0.0/16","172.29.0.0/16"]
  }
  ingress {
    description = "Inbound to vpc endpoints"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.29.0.0/16","172.29.0.0/16"]
  }
}

resource "aws_vpc_endpoint" "vpce" {
  vpc_id              = var.vpc_id
  service_name        = format("com.amazonaws.%s.%s", data.aws_region.current.name, var.vpc_endpoint_service_name)
  vpc_endpoint_type   = "Interface"
  security_group_ids  = [aws_security_group.vpc_endpoint_sec_group.id]
  subnet_ids          = var.vpc_endpoint_subnet_ids
  private_dns_enabled = false
  tags = merge(
    {
      "Name" = format("%s-%s-%s-vpce-%s", var.master_prefix, var.env_prefix, var.app_prefix, var.vpc_endpoint_service_name)
    },
    var.tags, var.vpc_tags
  )
}

resource "aws_route53_zone" "phz_vpc_endpoints" {
  name    = format("%s.%s.amazonaws.com", var.vpc_endpoint_service_name, data.aws_region.current.name)
  comment = format("Private hosted zone for VPC Endpoint %s.%s.amazonaws.com", var.vpc_endpoint_service_name, data.aws_region.current.name)
  vpc {
    vpc_id = var.vpc_id
  }
  tags = merge(
    {
      "Name" = format("%s-%s-%s-vpce-%s", var.master_prefix, var.env_prefix, var.app_prefix, var.vpc_endpoint_service_name)
    },
    var.tags, var.vpc_tags
  )
  lifecycle {
    ignore_changes = [
      # The private hosted zone will be attached to multiple VPCs. 
      # These associations must be retained. Hence ignore changes to the vpc argument. If removed will cause drift and lead to disassociing the VPC
      vpc
    ]
  }
}

resource "aws_route53_record" "r53_alias_vpc_endpoint" {
  zone_id = aws_route53_zone.phz_vpc_endpoints.zone_id
  name    = format("%s.%s.amazonaws.com", var.vpc_endpoint_service_name, data.aws_region.current.name)
  type    = "A"
  alias {
    name                   = aws_vpc_endpoint.vpce.dns_entry[0].dns_name
    zone_id                = aws_vpc_endpoint.vpce.dns_entry[0].hosted_zone_id
    evaluate_target_health = true
  }
}

=======================================================================

variable "vpc_endpoint_services" { type = list(string) description = "List of services for which VPC Endpoints nad their Route 53 Private Hosted Zones will be created" } 

vpc_endpoint_services = ["ssmmessages", "ssm", "ec2messages", "secretsmanager", "git-codecommit", "datasync", "kms", "logs", "sts", "email-smtp"]

Hi, Welcome to the forum - please reformat your message

Hi maxb, done. Please see if its ok. Thanks.

Thank you for that.

I can see in your configuration that you are using provider aliases:

However, this seems like a pretty unusual thing to be doing, as usually provider aliases are only used when you need multiple configurations of the same provider in a configuration.

At least from what you’ve shared so far, this doesn’t appear to be the case.

Do you have additional configurations of the hashicorp/aws provider within this configuration, that do not appear in the excerpts you have shared so far?

Depending on your answer to that question, I would make substantially different recommendations.

Actually, whatever the answer to that, I think the first step of improving this configuration will be to remove the provider "aws" { ... } blocks from all of the child modules, and make sure you can run a Terraform apply, and that repeated applys don’t make further changes.

Once that’s done and out of the way, we can talk about further cleanup (which will differ depending on the answer to the question).

HI maxb,

You are right! I do have multiple configurations of the same provider. But did not show as I thought its irrelevant. I have added it back to the provider.tf files in the main question.

Thanks.

#Provider for Network Account
provider "aws" {
  region              = var.region_name
  alias               = "networking"
  shared_config_files = ["./config"]
  profile             = "AWSAFTExecution"
  assume_role {
    role_arn = "arn:aws:iam::${data.aws_ssm_parameter.network_acc_number.value}:role/AWSAFTExecution"
  }
  default_tags {
    tags = var.tags
  }
} 

OK, this is all making sense now… it’s pretty complicated, so I’ll try to break it down:

First, let’s talk about your original error message:

In the early days of Terraform, it was allowed to define provider configurations in the root module, or in child modules. However, it later became clear that there were problems with allowing provider configurations to be specified in child modules. (You can read more about this in Providers in Modules? for background information, if you like.)

When support for count, for_each, and depends_on was added to module blocks, it was decided to only support them for child modules which did NOT define their own provider configurations.

You receive the error because you have attempted to use count, but your child module defines provider configurations.

However, your child module doesn’t seem to actually be using the provider configurations it defines!

In the root module, you set up two provider configurations:

and then in each of the module blocks you showed, you include:

By writing this, you are telling Terraform that the child module’s default aws provider configuration (with no alias) should be the root module’s aws.sharedservices provider configuration - effectively you’re passing the provider configuration by reference, effectively renaming it within the child module.

When I look at the resource blocks from the child module that you shared, I don’t see any lines looking like

  provider = aws.something

This tells me that everything in the child module is using the default (no alias) aws provider there. That means that the extra provider "aws" configuration blocks in the child module are in fact completely redundant and should be removed!

Since these redundant provider configurations are what are causing Terraform to block the usage of count on your module in the first place, cleaning up this redundancy should solve your problem!

Hi maxb,

I refactored my code according to your recommendations. But got this errors (many Error: Provider configuration not present) instead, could you advised what I did wrongly? If these errors regarding vpc endpoint is fixed, the rest should be the same issue.

Please bear with me for a while as I am new to Terraform and had only done 2 implementations from scratch and I am only using Terraform on and off.

Thanks.


D:\AWS_LZ1\abc-prod-shared-services\abc-prod-shared-services>terraform plan
?
¦ Warning: Reference to undefined provider
¦
¦   on aws_config_alerts.tf line 11, in module "aws_config_compliance_alerts":
¦   11:       aws = aws.sharedservices
¦
¦ There is no explicit declaration for local provider name "aws" in module.aws_config_compliance_alerts, so Terraform is assuming you mean to pass a
¦ configuration for "hashicorp/aws".
¦
¦ If you also control the child module, add a required_providers entry named "aws" with the source address "hashicorp/aws".
¦
¦ (and 21 more similar warnings elsewhere)
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.s3_vpc_endpoint.aws_route53_zone.phz_vpc_endpoints its original provider configuration at
¦ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_route53_zone.phz_vpc_endpoints, after which you can remove the provider configuration again.
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.s3_vpc_endpoint.aws_route53_record.r53_alias_vpc_endpoint its original provider configuration at
¦ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_route53_record.r53_alias_vpc_endpoint, after which you can remove the provider configuration again.
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.vpc_endpoints-ecr-dkr.aws_route53_zone.phz_vpc_endpoints its original provider configuration at
¦ module.vpc_endpoints-ecr-dkr.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-dkr.aws_route53_zone.phz_vpc_endpoints, after which you can remove the provider configuration again.
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.vpc_endpoints-ecr-api.aws_vpc_endpoint.vpce its original provider configuration at
¦ module.vpc_endpoints-ecr-api.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-api.aws_vpc_endpoint.vpce, after which you can remove the provider configuration again.
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.vpc_endpoints-ecr-api.aws_route53_zone.phz_vpc_endpoints its original provider configuration at
¦ module.vpc_endpoints-ecr-api.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-api.aws_route53_zone.phz_vpc_endpoints, after which you can remove the provider configuration again.
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.s3_vpc_endpoint.aws_vpc_endpoint.vpce its original provider configuration at
¦ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_vpc_endpoint.vpce, after which you can remove the provider configuration again.
?
?
¦ Error: Provider configuration not present
¦
¦ To work with module.s3_vpc_endpoint.aws_security_group.vpc_endpoint_sec_group its original provider configuration at
¦ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_security_group.vpc_endpoint_sec_group, after which you can remove the provider configuration again.
?
........
.......
.....
....
...
.


 Directory of D:\AWS_LZ1\abc-prod-shared-services\abc-prod-shared-services

24/04/2023  05:26 PM    <DIR>          .
24/04/2023  05:26 PM    <DIR>          ..
20/04/2023  01:37 PM             1,590 buildspec_apply.yaml
20/04/2023  01:37 PM             1,661 buildspec_plan.yaml
24/04/2023  05:26 PM    <DIR>          lz-sharedservices
24/04/2023  05:26 PM    <DIR>          lz-tf-modules
20/04/2023  01:37 PM            50,065 README.md
               3 File(s)         53,316 bytes
               4 Dir(s)  13,893,246,976 bytes free


 Directory of D:\AWS_LZ1\abc-prod-shared-services\abc-prod-shared-services\lz-sharedservices

24/04/2023  05:26 PM    <DIR>          .
24/04/2023  05:26 PM    <DIR>          ..
24/04/2023  05:26 PM    <DIR>          .terraform
20/04/2023  01:38 PM             3,472 .terraform.lock.hcl
20/04/2023  02:03 PM             1,073 acm.tf
20/04/2023  02:03 PM             6,707 ad-client.tf
20/04/2023  02:03 PM             1,271 ad.tf
20/04/2023  03:54 PM               481 aws_config_alerts.tf
20/04/2023  03:54 PM               504 budget_alerts.tf
20/04/2023  01:45 PM               908 cloudhsm.tf
20/04/2023  01:45 PM             1,013 cloudhsm_prod.tf
20/04/2023  01:37 PM               264 config
20/04/2023  02:10 PM             1,566 cw_alarms.tf
20/04/2023  01:37 PM             3,195 data_sources.tf
20/04/2023  03:01 PM             7,015 dns.tf
20/04/2023  02:10 PM             1,205 iam.tf
20/04/2023  02:10 PM             1,102 kms.tf
20/04/2023  01:37 PM             1,574 output.tf
20/04/2023  02:10 PM             1,071 prefix_list.tf
20/04/2023  02:10 PM             6,066 privateHostedZone.tf
24/04/2023  05:37 PM               807 provider.tf  <--- (Only one provider file in root module)
20/04/2023  02:10 PM             4,827 publicHostedZone.tf
20/04/2023  02:10 PM             3,436 ram.tf
20/04/2023  02:10 PM               754 secrets_manager.tf
20/04/2023  02:10 PM             3,760 ssm_parameters.tf
20/04/2023  01:37 PM             4,887 terraform.tfvars
20/04/2023  01:37 PM            11,545 variables.tf
24/04/2023  05:38 PM             3,543 vpc-endpoints.tf
20/04/2023  02:10 PM             3,182 vpc.tf
              30 File(s)         83,572 bytes
               3 Dir(s)  13,893,246,976 bytes free

provider.tf
=============

# Provider for Shared Services
provider "aws" {
  region = var.region_name
  alias  = "sharedservices"
  default_tags {
    tags = var.tags
  }
}

#Provider for Network Account
provider "aws" {
  region = var.region_name
  alias  = "networking"
  shared_config_files = ["./config"]
  profile = "AWSAFTExecution"
  assume_role {
    role_arn = "arn:aws:iam::${data.aws_ssm_parameter.network_acc_number.value}:role/AWSAFTExecution"
  }
  default_tags {
    tags = var.tags
  }
}

terraform {
  backend "s3" {
    bucket         = "abc-prod-ss-infra-aft-tfstate-ap-northeast-1-001234567890"
    key            = "02-shared-services/terraform.tfstate"
    region         = "ap-northeast-1"
    dynamodb_table = "abc-prod-ss-infra-aft-tf-state-lock"
    encrypt        = true
  }
}

variables.tf
==============

variable "vpc_endpoint_services" {
  type        = list(string)
  description = "List of services for which VPC Endpoints nad their Route 53 Private Hosted Zones will be created"
}

terraform.tfvars
=================

vpc_endpoint_services    = ["ssmmessages", "ssm", "ec2messages", "secretsmanager", "git-codecommit", "datasync", "kms", "logs", "sts", "email-smtp"]

vpc-endpoints.tf (In root module)
==================

locals {
  vpc_endpoint_subnet_ids = [for subnet in module.vpc.subnet_list.* : subnet.id if subnet.tags.SubnetName == var.vpc_endpoint_subnet_name]
}

module "vpc_endpoints" {
  count                     = length(var.vpc_endpoint_services)
  source                    = "../lz-tf-modules/vpc-endpoint/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = var.vpc_endpoint_services[count.index]
  master_prefix             = var.master_prefix
  env_prefix                = var.env_prefix
  app_prefix                = var.app_prefix
  #tags                      = var.tags
  vpc_tags = var.vpc_tags

      providers = {
      aws = aws.sharedservices
    }
}

# # # Separate VPC endpoint for S3. All spoke VPCs have the option of us S3 Gateway endpoint. This endpoint's primary purpose is to serve on-prem to S3 traffic via Direct Connect
module "s3_vpc_endpoint" {
  count                     = var.enable_s3_vpc_interface_endpoint ? 1 : 0
  source                    = "../lz-tf-modules/vpc-endpoint/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = "s3"
  master_prefix             = var.master_prefix
  env_prefix                = var.env_prefix
  app_prefix                = var.app_prefix
  #tags                      = var.tags
  vpc_tags = var.vpc_tags

      providers = {
      aws = aws.sharedservices
    }
}

# #Record to allow s3 virtual-hosted-style URL
resource "aws_route53_record" "s3" {
  zone_id = module.s3_vpc_endpoint[0].r53_zone_id
  name    = "*"
  type    = "CNAME"
  ttl     = "300"
  records = ["s3.${data.aws_region.current.name}.amazonaws.com"]
     provider          = aws.sharedservices
}

module "vpc_endpoints-ecr-api" {
  count                     = length(var.vpc_endpoint_services)
  source                    = "../lz-tf-modules/vpc-endpoint-custom-dns/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = "ecr.api"
  vpc_endpoint_dns_name     = "api.ecr"
  master_prefix             = var.master_prefix
  env_prefix                = var.env_prefix
  app_prefix                = var.app_prefix
  #tags                      = var.tags
  vpc_tags = var.vpc_tags

      providers = {
      aws = aws.sharedservices
    }
}

module "vpc_endpoints-ecr-dkr" {
  count                     = length(var.vpc_endpoint_services)
  source                    = "../lz-tf-modules/vpc-endpoint-custom-dns/"
  vpc_id                    = module.vpc.vpc_id
  vpc_endpoint_subnet_ids   = local.vpc_endpoint_subnet_ids
  vpc_endpoint_service_name = "ecr.dkr"
  vpc_endpoint_dns_name     = "dkr.ecr"
  master_prefix             = var.master_prefix
  env_prefix                = var.env_prefix
  app_prefix                = var.app_prefix
  #tags                      = var.tags
  vpc_tags = var.vpc_tags

      providers = {
      aws = aws.sharedservices
    }
}

#Record to allow ekr dkr virtual-hosted-style URL
resource "aws_route53_record" "r53_alias_vpc_endpoint" {
  zone_id = module.vpc_endpoints-ecr-dkr.r53_zone_id
  name    = format("*.dkr.ecr.%s.amazonaws.com", data.aws_region.current.name)
  type    = "CNAME"
  ttl     = "300"
  records = [module.vpc_endpoints-ecr-dkr.vpc_endpoint_dns_entry[0]["dns_name"]]
     provider          = aws.sharedservices
}

**** No provider file in child module folder ****

 Directory of D:\AWS_LZ1\abc-prod-shared-services\abc-prod-shared-services\lz-tf-modules\vpc-endpoint

24/04/2023  05:26 PM    <DIR>          .
24/04/2023  05:26 PM    <DIR>          ..
24/04/2023  05:40 PM             2,930 main.tf
20/04/2023  01:37 PM               388 outputs.tf
20/04/2023  01:37 PM             1,942 README.md
20/04/2023  01:37 PM               970 variables.tf
               5 File(s)          6,356 bytes
               2 Dir(s)  13,893,242,880 bytes free

main.tf
==========

data "aws_region" "current" {}

resource "aws_security_group" "vpc_endpoint_sec_group" {
  name        = format("%s-%s-%s-vpc-endpoint-%s", var.master_prefix, var.env_prefix, var.app_prefix, var.vpc_endpoint_service_name)
  description = format("Security Group for VPC Endpoint com.amazonaws.%s.%s", data.aws_region.current.name, var.vpc_endpoint_service_name)
  vpc_id      = var.vpc_id

  egress {
    description = "Outbound to vpc endpoints"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.29.0.0/16","172.29.0.0/16"]
  }
  ingress {
    description = "Inbound to vpc endpoints"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.29.0.0/16","172.29.0.0/16"]
  }
    provider          = aws.sharedservices<--- (Added this line as advised in previous thread to reference to the correct alias configuration)
}

resource "aws_vpc_endpoint" "vpce" {
  vpc_id              = var.vpc_id
  service_name        = format("com.amazonaws.%s.%s", data.aws_region.current.name, var.vpc_endpoint_service_name)
  vpc_endpoint_type   = "Interface"
  security_group_ids  = [aws_security_group.vpc_endpoint_sec_group.id]
  subnet_ids          = var.vpc_endpoint_subnet_ids
  private_dns_enabled = false
  tags = merge(
    {
      "Name" = format("%s-%s-%s-vpce-%s", var.master_prefix, var.env_prefix, var.app_prefix, var.vpc_endpoint_service_name)
    },
    var.tags, var.vpc_tags
  )
    provider          = aws.sharedservices
}

resource "aws_route53_zone" "phz_vpc_endpoints" {
  #checkov:skip=CKV2_AWS_38:Skip the check for Private Hosted Zone
  #checkov:skip=CKV2_AWS_39:Skip the check as we have enabled query log in the VPC level
  name    = format("%s.%s.amazonaws.com", var.vpc_endpoint_service_name, data.aws_region.current.name)
  comment = format("Private hosted zone for VPC Endpoint %s.%s.amazonaws.com", var.vpc_endpoint_service_name, data.aws_region.current.name)
  vpc {
    vpc_id = var.vpc_id
  }
  tags = merge(
    {
      "Name" = format("%s-%s-%s-vpce-%s", var.master_prefix, var.env_prefix, var.app_prefix, var.vpc_endpoint_service_name)
    },
    var.tags, var.vpc_tags
  )
  lifecycle {
    ignore_changes = [
      # The private hosted zone will be attached to multiple VPCs. 
      # These associations must be retained. Hence ignore changes to the vpc argument. If removed will cause drift and lead to disassociing the VPC
      vpc
    ]
  }
    provider          = aws.sharedservices
}

resource "aws_route53_record" "r53_alias_vpc_endpoint" {
  zone_id = aws_route53_zone.phz_vpc_endpoints.zone_id
  name    = format("%s.%s.amazonaws.com", var.vpc_endpoint_service_name, data.aws_region.current.name)
  type    = "A"
  alias {
    name                   = aws_vpc_endpoint.vpce.dns_entry[0].dns_name
    zone_id                = aws_vpc_endpoint.vpce.dns_entry[0].hosted_zone_id
    evaluate_target_health = true
  }
    provider          = aws.sharedservices


This warning is because you have removed too much from your child modules. You should have removed the provider "aws" { } blocks only, but you additionally removed the terraform { required_providers { } } blocks too. Add those back.

These errors, with the exact details shown, imply that you have excessively simplified some of the previous code examples - the error messages report objects managed by providers with aliases, but there is no provider = ... line in the resource "aws_vpc_endpoint" "vpce" block in the code you showed earlier, which contradicts this.

In order to allow me to give good advice about next steps, I need to accurately see your current code. It would be better if you could share it in a Git repository, as it is too complicated to effectively share in a forum post, especially where it is really important to know which directory various files are located in.

Hi maxb,

I messaged you the location of the repository. I put back only the terraform block as mentioned but still am getting the errors.

Thanks.


D:\AWS_LZ2\abc-prod-shared-services\lz-sharedservices>terraform plan

│ Warning: Reference to undefined provider

│

│ on aws_config_alerts.tf line 11, in module "aws_config_compliance_alerts":

│ 11: aws = aws.sharedservices

│

│ There is no explicit declaration for local provider name "aws" in module.aws_config_compliance_alerts, so Terraform is assuming you mean to pass a configuration for "hashicorp/aws".

│

│ If you also control the child module, add a required_providers entry named "aws" with the source address "hashicorp/aws".

│

│ (and 19 more similar warnings elsewhere)

╵

╵

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-dkr.aws_route53_record.r53_alias_vpc_endpoint its original provider configuration at

│ module.vpc_endpoints-ecr-dkr.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-dkr.aws_route53_record.r53_alias_vpc_endpoint, after which you

│ can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-dkr.aws_route53_zone.phz_vpc_endpoints its original provider configuration at

│ module.vpc_endpoints-ecr-dkr.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-dkr.aws_route53_zone.phz_vpc_endpoints, after which you can

│ remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints.aws_route53_zone.phz_vpc_endpoints its original provider configuration at module.vpc_endpoints.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints.aws_route53_zone.phz_vpc_endpoints, after which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-dkr.aws_vpc_endpoint.vpce its original provider configuration at module.vpc_endpoints-ecr-dkr.provider["registry.terraform.io/hashicorp/aws"].sharedservices

│ 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.vpc_endpoints-ecr-dkr.aws_vpc_endpoint.vpce, after which you can remove the provider configuration again.

╵

│ Error: Provider configuration not present

│

│ To work with module.s3_vpc_endpoint.aws_vpc_endpoint.vpce its original provider configuration at module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_vpc_endpoint.vpce, after which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints.aws_security_group.vpc_endpoint_sec_group its original provider configuration at

│ module.vpc_endpoints.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints.aws_security_group.vpc_endpoint_sec_group, after which you can remove the

│ provider configuration again.

╵

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints.aws_route53_record.r53_alias_vpc_endpoint its original provider configuration at

│ module.vpc_endpoints.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints.aws_route53_record.r53_alias_vpc_endpoint, after which you can remove the

│ provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints.aws_vpc_endpoint.vpce its original provider configuration at module.vpc_endpoints.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints.aws_vpc_endpoint.vpce, after which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-api.aws_route53_record.r53_alias_vpc_endpoint its original provider configuration at

│ module.vpc_endpoints-ecr-api.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-api.aws_route53_record.r53_alias_vpc_endpoint, after which you

│ can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-api.aws_route53_zone.phz_vpc_endpoints its original provider configuration at

│ module.vpc_endpoints-ecr-api.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-api.aws_route53_zone.phz_vpc_endpoints, after which you can

│ remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.hsm-vpc-prod.aws_route_table_association.private_route_table_association_webapp its original provider configuration at

│ module.hsm-vpc-prod.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.hsm-vpc-prod.aws_route_table_association.private_route_table_association_webapp, after

│ which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.hsm-vpc.aws_vpc.vpc its original provider configuration at module.hsm-vpc.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.hsm-vpc.aws_vpc.vpc,

│ after which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.hsm-vpc.aws_flow_log.fl its original provider configuration at module.hsm-vpc.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.hsm-vpc.aws_flow_log.fl, after which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-api.aws_vpc_endpoint.vpce its original provider configuration at module.vpc_endpoints-ecr-api.provider["registry.terraform.io/hashicorp/aws"].sharedservices

│ 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.vpc_endpoints-ecr-api.aws_vpc_endpoint.vpce, after which you can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.AWS_CloudHSM.aws_cloudhsm_v2_cluster.cloudhsm_cluster its original provider configuration at

│ module.AWS_CloudHSM.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.AWS_CloudHSM.aws_cloudhsm_v2_cluster.cloudhsm_cluster, after which you can remove the

│ provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.s3_vpc_endpoint.aws_route53_zone.phz_vpc_endpoints its original provider configuration at

│ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_route53_zone.phz_vpc_endpoints, after which you can remove the provider

│ configuration again.

╵

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-api.aws_security_group.vpc_endpoint_sec_group its original provider configuration at

│ module.vpc_endpoints-ecr-api.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-api.aws_security_group.vpc_endpoint_sec_group, after which you

│ can remove the provider configuration again.

╵

│ Error: Provider configuration not present

│

│ To work with module.s3_vpc_endpoint.aws_security_group.vpc_endpoint_sec_group its original provider configuration at

│ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_security_group.vpc_endpoint_sec_group, after which you can remove the

│ provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.vpc_endpoints-ecr-dkr.aws_security_group.vpc_endpoint_sec_group its original provider configuration at

│ module.vpc_endpoints-ecr-dkr.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.vpc_endpoints-ecr-dkr.aws_security_group.vpc_endpoint_sec_group, after which you

│ can remove the provider configuration again.

╵

╷

│ Error: Provider configuration not present

│

│ To work with module.s3_vpc_endpoint.aws_route53_record.r53_alias_vpc_endpoint its original provider configuration at

│ module.s3_vpc_endpoint.provider["registry.terraform.io/hashicorp/aws"].sharedservices 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.s3_vpc_endpoint.aws_route53_record.r53_alias_vpc_endpoint, after which you can remove the

│ provider configuration again.

Thank you for sharing the Git repository. Since you shared it privately, I won’t mention the URL here in this public thread - but since it is a public repository, anyone who knows your GitHub username would be able to find it by browsing your profile. In future, when sharing repositories that you don’t want to be public, you should mark them as private and share with individual collaborators.

The key difference between what you shared here and in Git, is that in Git, each of your resource blocks inside the child modules contains a line

  provider = aws.sharedservices

Let me take a step back and recap the configuration you had at the start of this thread:

  • In your root module, you defined two aws provider configurations - one with the alias sharedservices, the other with the alias networking
  • In each module block in your root module, you explicitly passed down the root module’s aws.sharedservices provider, making it the default aws provider with no alias, in the scope of the child module
  • Presumably because of a misunderstanding, you then went on to define a whole new aws provider configuration, also with the alias sharedservices inside each child module!!!
  • Within each child module, for your data blocks, you did not override the provider - so using the aws provider configuration passed down from the root module. Yet, for your resource blocks you instead specified provider = aws.sharedservices, making them use the aws provider configuration defined inside the child module.

This overcomplicated arrangement still worked OK, since you set up all of the many aws.sharedservices providers defined across many modules in roughly the same way … until you wanted to use count/for_each with modules, which disallows this configuration.

I believe the target configuration you should move towards, is to properly make use of the provider configuration being passed down from the root module to the child modules.

According to the code in Git you shared, you are nearly there, but you need to remove all of the

  provider = aws.sharedservices

lines from your child modules. (In your root module, at least for now, your provider config should remain as is, to minimize changes being made.)

There is one further detail to be aware of. The fact that all your resources in modules, were created using provider configurations defined inside the child modules, is currently recorded in your state file.

When you update all your modules to properly use the passed in providers, Terraform will update the state file accordingly … for all resources which still exist in your Terraform configuration files. If you’ve removed any resource blocks from your configuration, expecting Terraform to delete the relevant resources from AWS, you need to let that deletion be applied first, before attempting this refactor.

Hopefully that makes this complex topic clearer!

Hi maxb,

I tried it and the errors are gone now. Thanks so much for your help.