Fix Terraform AWS Provider: No Valid Credential Sources Found

Tested on Ubuntu 26.04 LTS (Resolute Raccoon)
Package terraform 1.16.1
hashicorp/aws 6.63.0
awscli 2.36.38
Applies to Any host with Terraform and the AWS provider; examples use ap-south-1
Lab environment Ubuntu workstation with AWS account access — Terraform lab environment on Ubuntu
Privilege AWS identity with sts:GetCallerIdentity; normal user on the workstation
Scope Reproduce No valid credential sources found for the HashiCorp AWS provider, then fix it with shared credentials, environment variables, named profiles, aws configure export-credentials, IAM Identity Center (SSO) profiles, and EC2 instance roles — including precedence when more than one source is present. Does not cover IAM policy design, multi-account organization setup, or non-AWS providers.
Short on time?Beta Get the gist of this 10-minute read in seconds, then ask follow-up questions

The first time you point Terraform at AWS, this error stops the run cold:

text
Error: No valid credential sources found

It usually means the AWS provider plugin could not find keys, a profile, SSO session, or an instance role — not that Terraform itself is broken. The confusing part is that aws sts get-caller-identity may still work in the same terminal while terraform plan fails.

This guide walks through every common credential source beginners use and how to wire each one into Terraform.

NOTE
For stage-by-stage Terraform debugging beyond AWS auth, see Terraform troubleshooting. For provider block syntax and aliases, see Terraform providers.

What this Terraform AWS error means

When Terraform plans or applies an AWS resource, the provider must sign API requests. If every credential source in the chain is empty or unreachable, you get:

  • Error: No valid credential sources found — headline from the AWS provider
  • A second line about EC2 IMDS on laptops and CI runners — Terraform also tried the instance metadata service at 169.254.169.254 and failed

That IMDS tail is normal on a workstation. It does not mean you must run Terraform on EC2 — it only means no instance role was found as a last resort.

Common situations that trigger it:

  • ~/.aws/credentials is missing or empty
  • You signed in with aws login but never exported session variables for Terraform
  • AWS_PROFILE or profile in the provider block points at a profile that does not exist
  • Environment variables were set in one shell tab but Terraform runs in another
  • You copied a tutorial that assumes an EC2 instance role you do not have

Reproduce the credential error

From your Terraform project directory, add a minimal AWS data source if you need a quick test target:

hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

provider "aws" {
  region = "ap-south-1"
}

data "aws_caller_identity" "current" {}

output "account_id" {
  value = data.aws_caller_identity.current.account_id
}

Initialize providers:

bash
terraform init

Strip every AWS credential source and run plan — this simulates a clean CI job or a new laptop:

bash
env -i HOME="$HOME" PATH="$PATH" USER="$USER" \
  AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null \
  terraform plan

Sample output:

output
Error: No valid credential sources found

  with provider["registry.terraform.io/hashicorp/aws"],
  on main.tf line 10, in provider "aws":
  10: provider "aws" {

Error: failed to refresh cached credentials, no EC2 IMDS role found,
operation error ec2imds: GetMetadata, exceeded maximum number of attempts, 3,
request send failed, Get
"http://169.254.169.254/latest/meta-data/iam/security-credentials/": dial tcp
169.254.169.254:80: connect: connection refused

You have reproduced the failure. The fixes below add credentials back one source at a time.


AWS provider credential precedence

The HashiCorp AWS provider uses the AWS SDK for Go v2 credential chain. HashiCorp documents this precedence order:

Priority Source Typical example
1 Provider configuration Explicit credentials, profile, or assume_role in provider "aws"
2 Environment / web identity AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, or OIDC via AWS_WEB_IDENTITY_TOKEN_FILE
3 Shared credentials ~/.aws/credentials
4 Shared config Profiles, SSO, assume_role, credential_process in ~/.aws/config
5 Container credentials ECS task role
6 Instance metadata EC2 instance profile (IMDS)

Precedence gotchas worth remembering:

  • If the provider block sets profile = "my-profile", that profile must exist in the shared files — valid environment variables alone do not override a missing profile name
  • If profile is not set, environment variables can satisfy Terraform even when credential files are absent
  • The AWS CLI and Terraform can use many of the same AWS configuration files and environment variables, but they do not use the same underlying SDK. If the CLI works while Terraform fails, compare AWS_* variables, AWS_PROFILE, the shared config/credentials files, and any profile argument in the provider block

Fix with ~/.aws/credentials

If you already use an IAM access key, the AWS provider can read it from ~/.aws/credentials. Long-lived access keys are not the preferred setup for new local-development environments, but this remains a common source worth checking when troubleshooting older configurations.

After installing the AWS CLI, you can create or update a profile with:

bash
aws configure

That creates entries like:

ini
[default]
aws_access_key_id = AKIAEXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

And region in ~/.aws/config:

ini
[default]
region = ap-south-1
output = json

With files in place, run plan from the same directory (no env -i wrapper):

bash
terraform plan

Sample output:

output
Changes to Outputs:
  + account_id = "342524208658"

Plan: 0 to add, 0 to change, 0 to destroy.

The plan succeeds because Terraform reads the default profile from the shared credentials file.


Fix with AWS environment variables

CI pipelines, containers, and GitHub Actions often supply temporary credentials as environment variables instead of writing ~/.aws/credentials.

Export credentials for the current shell:

bash
export AWS_ACCESS_KEY_ID="AKIAEXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="ap-south-1"

If you use temporary credentials (SSO or assumed role), also set AWS_SESSION_TOKEN.

Run plan with credential files hidden to prove env vars alone are enough:

bash
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null terraform plan

Sample output:

output
Changes to Outputs:
  + account_id = "342524208658"

On a real workstation, the fastest way to populate those variables from an existing CLI session is:

bash
eval "$(aws configure export-credentials --format env)"

That one line is the fix when aws sts get-caller-identity works but Terraform still reports no credential sources — common after aws login on CLI v2.32+.


Fix with a named AWS profile

A named profile selects a specific AWS configuration when one workstation uses multiple identities or accounts. The simplest legacy example is an access-key profile in ~/.aws/credentials:

ini
[terraform-lab]
aws_access_key_id = AKIAEXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

Profiles can also represent IAM Identity Center, assume_role chains, or credential_process entries in ~/.aws/config — the SSO section below covers that pattern.

Point the provider at a credentials-file profile:

hcl
provider "aws" {
  region  = "ap-south-1"
  profile = "terraform-lab"
}

Run plan with explicit file paths if you keep profiles outside the default location:

bash
export AWS_SHARED_CREDENTIALS_FILE=~/.aws/credentials
export AWS_CONFIG_FILE=~/.aws/config
terraform plan

Terraform loads terraform-lab from the credentials file. A typo in the profile name fails immediately:

output
Error: failed to get shared config profile, nonexistent-profile

Fix the spelling in provider "aws" or create the missing profile — environment variables do not rescue a bad profile argument.


Fix when aws login works but Terraform fails

Modern AWS CLI can sign you in without long-lived access keys — see AWS CLI tutorial. aws login stores credentials in the AWS login cache. The Terraform AWS provider's Go SDK credential chain does not currently consume that login provider directly, so export the active CLI credentials into standard environment variables:

bash
eval "$(aws configure export-credentials --format env)"

That export is the common fix when:

text
aws sts get-caller-identity   # works
terraform plan              # fails

Verify the CLI identity first:

bash
aws sts get-caller-identity

Run plan again after export:

bash
terraform plan

The same pattern appears in cloud guides such as deploy EKS with Terraform — export credentials in every shell (or CI step) before terraform init, plan, or apply.

For scripts, chain export and Terraform in one line:

bash
eval "$(aws configure export-credentials --format env)" && terraform plan

Fix with IAM Identity Center SSO

Teams using IAM Identity Center (formerly AWS SSO) store SSO settings in ~/.aws/config, not in credentials:

ini
[profile corp-sso]
sso_start_url = https://my-org.awsapps.com/start
sso_region = ap-south-1
sso_account_id = 123456789012
sso_role_name = AdministratorAccess
region = ap-south-1

Workflow:

  1. Log in: aws sso login --profile corp-sso
  2. Point Terraform at the profile:
hcl
provider "aws" {
  region  = "ap-south-1"
  profile = "corp-sso"
}
  1. Run terraform plan in the same shell session before the SSO token expires

Alternatively, after aws sso login, use eval "$(aws configure export-credentials --profile corp-sso --format env)" so Terraform reads standard AWS_* variables.


Fix with an EC2 instance role

On an EC2 instance with an instance profile attached, Terraform needs no access keys in files or environment variables. The provider obtains temporary credentials through the instance metadata service (IMDS) automatically.

Minimal provider block on EC2:

hcl
provider "aws" {
  region = "ap-south-1"
}

Confirm the instance is using a role — with no file or environment credentials configured, run:

bash
aws sts get-caller-identity

If that succeeds on EC2, the CLI and provider may both be using the attached instance role.

On a laptop, the IMDS connection refused line inside the original error is normal — there is no instance role to fall back to. Run Terraform from EC2 (or supply credentials another way) when you need AWS API access from your workstation.


Compare AWS credential methods

Method Best for Terraform setup
~/.aws/credentials Legacy access-key setups, older labs Default provider block; optional profile
Environment variables CI/CD, containers, OIDC-fed pipelines export or eval "$(aws configure export-credentials …)"
Named profile Multiple identities on one machine profile = "name" in provider block
aws login / SSO Temporary console or SSO sessions aws login or aws sso login, then export env vars
EC2 instance role Runs on EC2 / some CI agents Provider block only; attach IAM instance profile

Troubleshooting

Symptom Likely cause Fix
aws sts works, Terraform fails Session lives in CLI cache only eval "$(aws configure export-credentials --format env)"
failed to get shared config profile profile in provider block is wrong Fix profile name or add section to ~/.aws/config
Worked yesterday, fails today Expired SSO or assumed-role session Re-run aws sso login or refresh credentials
IMDS error on a laptop Normal — no EC2 role present Use credentials file, env vars, or SSO — not IMDS
Worked in terminal A, not B Variables not exported in second shell Export AWS_* in the same shell that runs Terraform
AccessDenied instead of no credentials Auth succeeded; IAM policy denies API Attach permissions — different problem than missing keys

Summary

No valid credential sources found means the AWS provider exhausted its credential chain — shared files, environment variables, SSO profiles, and finally EC2 metadata. Reproduce it by hiding ~/.aws/* and unsetting AWS_* variables, then fix it by supplying one valid source.

On a developer laptop, eval "$(aws configure export-credentials --format env)" after aws login covers many modern setups; older ~/.aws/credentials access-key profiles still appear in the wild. In CI, prefer temporary credentials obtained through workload federation/OIDC or an assigned role. When the CI platform supplies temporary AWS credentials as environment variables, the provider reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. On EC2, attach an instance profile and keep keys out of code entirely.

When the CLI and Terraform disagree, compare the provider profile argument, active environment variables, and whether the shell running Terraform is the same one where you signed in. For backend and state issues after auth works, continue with Configure S3 bucket as Terraform backend.


References


Frequently Asked Questions

Why does Terraform try EC2 metadata on my laptop?

The AWS provider's credential chain checks every source in order, including the instance metadata service at 169.254.169.254. On non-EC2 hosts that request fails quickly. It is a fallback message, not a requirement to use EC2.

Is it safe to put access keys in the provider block?

Terraform accepts access_key and secret_key in provider "aws", but you should avoid it. Hard-coded credentials can leak through source control, copied configuration files, logs, or other tooling. Prefer environment variables, profiles, temporary credentials, or workload roles.

Do I need different credentials for the S3 backend and the AWS provider?

Usually no. The S3 backend and AWS provider can both use the standard AWS credential chain, so the same identity often authenticates both. They are configured separately, however, so you can give the backend a different profile, assume_role configuration, or other credential settings when needed.

Does terraform validate catch missing AWS credentials?

No. validate checks configuration syntax without calling AWS APIs. The credential error appears on plan or apply when the provider contacts AWS.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)