Initializing Enclave...

How to Fix 'No Valid Credential Sources for Terraform AWS Provider' (Complete Debugging Guide)

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 5–15 mins

TL;DR

  • What broke: Terraform's AWS provider credential chain exhausted every lookup path — env vars, shared credentials file, instance profile, ECS task role, OIDC — and found nothing valid.
  • How to fix it: Explicitly supply credentials via environment variables, an IAM instance/task role, or a properly configured OIDC federation block in the provider; never hardcode keys.
  • Shortcut: Use our Client-Side Sandbox below to auto-refactor this — paste your provider block and get a corrected config without leaking secrets to any server.

The Incident (What Does This Error Mean?)

Error: configuring Terraform AWS Provider:
  no valid credential sources for Terraform AWS Provider found.
  Please see https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication
  for valid configurations.
  Error: no EC2 IMDS role found, operation error ec2imds: GetMetadata

Terraform's AWS provider walks a strict credential chain at plan/apply time:

  1. Static keys in the provider block
  2. AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env vars
  3. AWS_PROFILE / ~/.aws/credentials shared file
  4. ECS task role via container metadata endpoint
  5. EC2 instance profile via IMDSv2
  6. Web Identity Token (OIDC) via AWS_WEB_IDENTITY_TOKEN_FILE

When every single one of those returns empty or errors, you get this message. The immediate consequence: terraform plan exits non-zero, your pipeline is dead, and no state changes can occur. In a CD pipeline this means a deployment freeze on whatever environment this provider targets.


The Attack Vector / Blast Radius

This error itself is not a direct exploit vector — but the conditions that cause it often are:

  • Hardcoded keys that got rotated or deleted — the old access_key/secret_key in the provider block are now dead. If those keys were ever committed to git, they are already in your history and potentially harvested by secret-scanning bots. Rotation fixed the auth, but the leaked key window already existed.
  • Overly broad keys with no rotation policy — teams that hardcode AWS_ACCESS_KEY_ID in CI/CD env vars tend to use long-lived, over-privileged keys. A single CI/CD platform breach (e.g., compromised GitHub Actions secret) hands an attacker static credentials with no expiry.
  • IMDS disabled on hardened AMIs — if your security team disabled IMDSv1 and your Terraform runner is not using IMDSv2 or has HttpTokens=required without the SDK configured for it, the instance profile lookup silently fails.
  • Blast radius of a successful exploit: An attacker with the leaked key inherits whatever IAM policy is attached — commonly AdministratorAccess on poorly governed accounts. Full account takeover in under 60 seconds via aws iam create-user + new access key.

How to Fix It (The Solution)

Basic Fix — Environment Variables (Quickest Unblock)

Set credentials in the shell or CI/CD secret store, keep the provider block clean:

- provider "aws" {
-   region     = "us-east-1"
-   access_key = "AKIAIOSFODNN7EXAMPLE"
-   secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
- }
+ provider "aws" {
+   region = "us-east-1"
+   # Credentials resolved from environment:
+   # AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
+ }

Then in your shell or CI secret injection:

export AWS_ACCESS_KEY_ID="$(vault kv get -field=key secret/aws/terraform)"
export AWS_SECRET_ACCESS_KEY="$(vault kv get -field=secret secret/aws/terraform)"
export AWS_SESSION_TOKEN="$(vault kv get -field=token secret/aws/terraform)"

Enterprise Best Practice — OIDC Federation (GitHub Actions / GitLab CI)

Zero long-lived keys. The CI runner exchanges a short-lived OIDC JWT for an assumed IAM role.

IAM Trust Policy (attach to your Terraform execution role):

- # No trust policy — role not assumable by CI
+ {
+   "Version": "2012-10-17",
+   "Statement": [{
+     "Effect": "Allow",
+     "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
+     "Action": "sts:AssumeRoleWithWebIdentity",
+     "Condition": {
+       "StringEquals": {
+         "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
+       },
+       "StringLike": {
+         "token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:*"
+       }
+     }
+   }]
+ }

GitHub Actions workflow:

- env:
-   AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
-   AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ permissions:
+   id-token: write
+   contents: read
+ steps:
+   - name: Configure AWS credentials via OIDC
+     uses: aws-actions/configure-aws-credentials@v4
+     with:
+       role-to-assume: arn:aws:iam::123456789012:role/terraform-ci-role
+       aws-region: us-east-1

Terraform provider block (no changes needed — env vars are set by the action):

- provider "aws" {
-   region     = "us-east-1"
-   access_key = var.aws_access_key
-   secret_key = var.aws_secret_key
- }
+ provider "aws" {
+   region = "us-east-1"
+ }

For EC2/ECS runners — ensure IMDSv2 is reachable:

- # Instance launched with HttpTokens=optional or IMDS disabled
+ resource "aws_instance" "terraform_runner" {
+   metadata_options {
+     http_endpoint               = "enabled"
+     http_tokens                 = "required"  # IMDSv2 enforced
+     http_put_response_hop_limit = 1
+   }
+ }

And ensure the AWS SDK/Terraform version is ≥ 4.x (IMDSv2-aware by default).


💡 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

1. Checkov — Block Hardcoded Keys at PR Time

Add to your pipeline:

- name: Checkov Scan
  uses: bridgecrewio/checkov-action@master
  with:
    directory: .
    check: CKV_AWS_41  # Ensure no hardcoded credentials in provider block

CKV_AWS_41 fails the build if access_key or secret_key are literal strings in any .tf file.

2. tfsec

tfsec . --include-passed --minimum-severity HIGH
# Flags: aws-iam-no-user-attached-policies, general-secrets-sensitive-in-attribute

3. OPA / Conftest Policy

# policy/no_hardcoded_aws_keys.rego
package terraform.aws.provider

deny[msg] {
  input.resource_changes[_].type == "provider"
  creds := input.resource_changes[_].change.after
  creds.access_key != ""
  msg := "DENY: Hardcoded AWS access_key in provider block. Use OIDC or instance profile."
}

Run in CI:

terraform show -json tfplan.binary | conftest test --policy policy/ -

4. git-secrets / Gitleaks Pre-commit Hook

gitleaks protect --staged --redact
# Blocks commits containing AKIA* patterns (AWS access key IDs)

5. Enforce required_providers Version Pinning

Older AWS provider versions had buggy IMDS fallback. Pin to a known-good version:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.30.0"  # Full IMDSv2 + OIDC support
    }
  }
}

Related Diagnostics

"Part of the Security Utility Matrix."

View all 140 Security Tools →