Initializing Enclave...

How to Fix 'Provider Configuration Not Set for AWS in Module' in Terraform

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 10 mins


TL;DR

  • What broke: A child module is consuming an aws provider that was never explicitly configured or passed from the root module — Terraform's provider inheritance does not work implicitly for aliased or multi-region providers.
  • How to fix it: Declare the provider in the root module and pass it to the child module via the providers meta-argument inside the module block.
  • Quick path: Use our Client-Side Sandbox below to auto-refactor this — paste your broken module call and get corrected HCL instantly without leaking your account IDs or ARNs.

The Incident (What Does the Error Mean?)

You hit this during terraform init, plan, or apply:

Error: Provider configuration not set for 'aws' in module

  on main.tf line 12, in module "vpc":
  12: module "vpc" {

The child module requires a provider named "aws" but no configuration
was passed for this provider. Either configure a provider with that
name in the module, or pass an existing provider configuration to
the module using the `providers` argument.

Immediate consequence: Terraform hard-stops. No plan is generated. No infrastructure is touched. Your pipeline is dead at the gate — but the real danger is what engineers do next: they start copy-pasting provider blocks inside child modules, which breaks reusability and creates drift.

This error is most common in three scenarios:

  1. Multi-region deployments — you've declared provider "aws" { alias = "us-west-2" } in root but forgot to wire it to the module.
  2. Refactored monorepos — a module was extracted from root and the provider wiring was never added back.
  3. Third-party modules — a registry module expects you to pass a specific provider alias it cannot self-configure.

The Attack Vector / Blast Radius

This isn't just a broken build — misunderstanding this error leads to architectural debt that compounds fast:

Blast Radius if misconfigured (not just unfixed):

  • Hardcoded provider blocks inside child modules destroy reusability. Every environment (dev/staging/prod) now requires forking the module instead of parameterizing the provider. You've just created three diverging codebases.
  • Implicit default provider reliance means if the default aws provider region is wrong (e.g., us-east-1 when you need eu-central-1), resources silently deploy to the wrong region. IAM policies, VPC peering, and KMS keys become region-mismatched. This is a data residency compliance violation in regulated environments (GDPR, FedRAMP).
  • In CI/CD pipelines, this error causes terraform plan to exit non-zero, blocking PRs — but if someone works around it by embedding credentials directly in the child module to satisfy the provider, you now have credential sprawl baked into module source code.
  • Multi-account architectures (AWS Organizations, Control Tower) are entirely broken by this pattern. The assume_role ARN in each account-specific provider never gets passed down, so every module call defaults to the pipeline's base role — completely undermining account isolation.

How to Fix It (The Solution)

Basic Fix — Pass the Default Provider

If you're using a single, non-aliased AWS provider, the child module should inherit it automatically unless the module's own required_providers block declares it explicitly. The fix is to ensure the root module's provider is wired:

# root/main.tf

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

 module "vpc" {
   source = "./modules/vpc"
+  providers = {
+    aws = aws
+  }
 }
# modules/vpc/versions.tf

 terraform {
   required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = ">= 5.0"
+    }
   }
 }

Enterprise Best Practice — Aliased Multi-Region / Multi-Account Providers

This is the pattern that breaks at scale. You have aliased providers for cross-region or cross-account deployments and the module call never maps them:

# root/main.tf — BROKEN

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

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

 module "dr_vpc" {
   source = "./modules/vpc"
-  # No providers argument — Terraform cannot infer which aliased provider to use
+  providers = {
+    aws = aws.west
+  }
 }
# modules/vpc/variables.tf — BROKEN (provider hardcoded inside module)

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

# modules/vpc/versions.tf — CORRECT (module declares requirement, root satisfies it)
+ terraform {
+   required_providers {
+     aws = {
+       source  = "hashicorp/aws"
+       version = ">= 5.0"
+     }
+   }
+ }

For multi-account (assume_role pattern):

# root/providers.tf

 provider "aws" {
   alias  = "prod_account"
   region = "us-east-1"
+  assume_role {
+    role_arn = "arn:aws:iam::123456789012:role/TerraformDeployRole"
+  }
 }

 module "prod_networking" {
   source = "./modules/networking"
+  providers = {
+    aws = aws.prod_account
+  }
 }

Rule: Child modules must never contain provider blocks with configuration. They declare required_providers for version constraints only. All provider configuration (region, credentials, assume_role) lives exclusively in the root module and is injected via providers = {}.


💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

Don't rely on engineers remembering this. Encode it:

1. terraform validate as a Pre-Commit Hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.83.5
    hooks:
      - id: terraform_validate
      - id: terraform_tflint

tflint with the AWS ruleset will flag missing provider configurations before they hit your pipeline.

2. Checkov Policy (Static Analysis)

checkov -d . --check CKV_TF_1

Add to your GitHub Actions or GitLab CI stage before terraform plan:

- name: Checkov Scan
  uses: bridgecrewio/checkov-action@master
  with:
    directory: .
    framework: terraform
    halt_on_broken_analyses: true

3. OPA / Conftest Policy (Enforce Provider Passthrough)

# policy/terraform/provider_passthrough.rego
package terraform.module_providers

deny[msg] {
  module := input.configuration.root_module.module_calls[name]
  not module.providers
  msg := sprintf(
    "Module '%s' has no explicit providers map. All module calls must declare a providers argument.",
    [name]
  )
}
terraform show -json tfplan.binary | conftest test --policy policy/ -

4. Terraform required_providers Version Pinning in Every Module

Make it a team standard: every modules/*/versions.tf file must exist and declare required_providers. A missing versions.tf in a module PR fails review. This surfaces the provider contract explicitly and prevents the silent inheritance assumption that causes this error.

Related Diagnostics

"Part of the Syntax Utility Matrix."

View all 153 Syntax Tools →