Terraform Version
1.16.3
Terraform Vault Provider Version
5.7.0 and later (working on 5.6.0)
Vault Server Version
2.0.2
Affected Resource(s)
Provider configuration — auth_login_aws with aws_profile
Expected Behavior
With credentials stored in the standard shared credentials file, auth_login_aws should resolve the named profile and authenticate to Vault, as it did in 5.6.0 and earlier.
Local setup (standard AWS CLI layout):
~/.aws/config
[example-profile]
region = eu-central-1
~/.aws/credentials
[example-profile]
aws_access_key_id = AKIA...
aws_secret_access_key = ...
aws_session_token = ...
Provider configuration:
provider "vault" {
address = "https://vault.example.com"
auth_login_aws {
role = "example-role"
aws_profile = "example-profile"
}
}
data "vault_kv_secret_v2" "example" {
mount = "secret"
name = "example"
}
Actual Behavior
With the configuration above:
Error: failed to get AWS credentials required for Vault login, err=failed to load SDK's
default configurations with given credential options: failed to get shared config profile,
example-profile
Setting AWS_PROFILE=example-profile instead of the aws_profile attribute does not help.
Steps to Reproduce
- Create
~/.aws/config and ~/.aws/credentials as shown above. No AWS_* environment
variables set.
- Pin the provider to 5.6.0, run
terraform plan — succeeds.
- Pin the provider to 5.7.0 or later, run
terraform plan — fails with the first error above.
Analysis
The regression appears to come from the awsutil v0 → awsutil/v2 migration in
#2679, and the root cause
looks like it is upstream in go-secure-stdlib, in generateAwsConfigOptions in
awsutil/generate_credentials.go.
Inside the withSharedCredentials branch, config.WithSharedCredentialsFiles is appended
unconditionally with CredentialsConfig.Filename. When Filename is empty — which it is
whenever aws_shared_credentials_file is not set — the SDK receives a one-element slice
holding an empty string.
The AWS SDK for Go v2 only applies DefaultSharedCredentialsFiles when the supplied slice is
empty (len == 0). A slice containing an empty string is not empty, so the default resolution
is skipped, the nonexistent path is silently ignored under ignoreNotExist, and
~/.aws/credentials is never read. Shared config files are unaffected, which is why the
region still resolves from ~/.aws/config while the credentials do not.
Notably, the sibling else branch a few lines above already guards the same call with a
Filename != "" check; the guard is missing on the unconditional call.
In AWS SDK for Go v1, which awsutil v0 was built on, an empty Filename on credentials.SharedCredentialsProvider is documented as "use the default location".
The empty string therefore changed meaning during the v1 → v2 migration: in v2 it is treated as a literal path.
Suggested direction
Guarding the WithSharedCredentialsFiles call so the option is only passed when a path was
actually configured would restore the SDK's own default resolution, and would also keep
AWS_SHARED_CREDENTIALS_FILE working — substituting a hardcoded default path instead would
break that environment variable.
If changing the shared library is undesirable (it is also consumed by Vault and Boundary), an
equivalent provider-side fix would be to populate Filename with the resolved default
credentials file path when aws_shared_credentials_file is not set.
Workaround
Setting the path explicitly makes Filename non-empty and restores the previous behavior:
auth_login_aws {
role = "example-role"
aws_profile = "example-profile"
aws_shared_credentials_file = pathexpand("~/.aws/credentials")
}
Terraform Version
1.16.3
Terraform Vault Provider Version
5.7.0 and later (working on 5.6.0)
Vault Server Version
2.0.2
Affected Resource(s)
Provider configuration —
auth_login_awswithaws_profileExpected Behavior
With credentials stored in the standard shared credentials file,
auth_login_awsshould resolve the named profile and authenticate to Vault, as it did in 5.6.0 and earlier.Local setup (standard AWS CLI layout):
~/.aws/config~/.aws/credentialsProvider configuration:
Actual Behavior
With the configuration above:
Setting
AWS_PROFILE=example-profileinstead of theaws_profileattribute does not help.Steps to Reproduce
~/.aws/configand~/.aws/credentialsas shown above. NoAWS_*environmentvariables set.
terraform plan— succeeds.terraform plan— fails with the first error above.Analysis
The regression appears to come from the
awsutilv0 →awsutil/v2migration in#2679, and the root cause
looks like it is upstream in
go-secure-stdlib, ingenerateAwsConfigOptionsinawsutil/generate_credentials.go.
Inside the
withSharedCredentialsbranch,config.WithSharedCredentialsFilesis appendedunconditionally with
CredentialsConfig.Filename. WhenFilenameis empty — which it iswhenever
aws_shared_credentials_fileis not set — the SDK receives a one-element sliceholding an empty string.
The AWS SDK for Go v2 only applies
DefaultSharedCredentialsFileswhen the supplied slice isempty (
len == 0). A slice containing an empty string is not empty, so the default resolutionis skipped, the nonexistent path is silently ignored under
ignoreNotExist, and~/.aws/credentialsis never read. Shared config files are unaffected, which is why theregion still resolves from
~/.aws/configwhile the credentials do not.Notably, the sibling
elsebranch a few lines above already guards the same call with aFilename != ""check; the guard is missing on the unconditional call.In AWS SDK for Go v1, which
awsutilv0 was built on, an empty Filename oncredentials.SharedCredentialsProvideris documented as "use the default location".The empty string therefore changed meaning during the v1 → v2 migration: in v2 it is treated as a literal path.
Suggested direction
Guarding the
WithSharedCredentialsFilescall so the option is only passed when a path wasactually configured would restore the SDK's own default resolution, and would also keep
AWS_SHARED_CREDENTIALS_FILEworking — substituting a hardcoded default path instead wouldbreak that environment variable.
If changing the shared library is undesirable (it is also consumed by Vault and Boundary), an
equivalent provider-side fix would be to populate
Filenamewith the resolved defaultcredentials file path when
aws_shared_credentials_fileis not set.Workaround
Setting the path explicitly makes
Filenamenon-empty and restores the previous behavior: