Skip to content

Commit 05814de

Browse files
authored
Better missing credentials error when using AWS modules (#375)
* Better missing credentials error when using AWS modules * embed error message and link to configuring explicit providers
1 parent abbfe2a commit 05814de

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

pkg/modprovider/error_message.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2016-2025, Pulumi Corporation.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package modprovider
16+
17+
import _ "embed"
18+
19+
//go:embed error_messages/aws_missing_credentials_error.txt
20+
var awsMissingCredentialsErrorMessage string
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
no valid credentials source found to configure the AWS provider.
2+
Consider supplying the required AWS credentials to the provider either via environment variables,
3+
or by configuring the provider explicitly in the Pulumi program with an explicit provider resource.
4+
See https://github.com/pulumi/pulumi-terraform-module?tab=readme-ov-file#configuring-terraform-providers.
5+
Alternatively, you can use Pulumi ESC to set up dynamic credentials with AWS OIDC.
6+
Learn more: https://www.pulumi.com/registry/packages/aws/installation-configuration/#dynamically-generate-credentials-via-pulumi-esc

pkg/modprovider/logger.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package modprovider
1616

1717
import (
1818
"context"
19+
"strings"
1920

2021
"github.com/pulumi/pulumi/pkg/v3/resource/provider"
2122
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
@@ -101,6 +102,12 @@ func newResourceLogger(hc *provider.HostClient, urn resource.URN) tfsandbox.Logg
101102
return &resourceLogger{hc: hc, urn: urn}
102103
}
103104

105+
func isMissingCredentialsErrorFromAWS(message string) bool {
106+
topLevelError := strings.Contains(message, "No valid credential sources found") ||
107+
strings.Contains(message, "Invalid provider configuration")
108+
return topLevelError && strings.Contains(message, "hashicorp/aws")
109+
}
110+
104111
func (l *resourceLogger) Log(ctx context.Context, level tfsandbox.LogLevel, message string) {
105112
if l.hc == nil {
106113
return
@@ -121,6 +128,12 @@ func (l *resourceLogger) Log(ctx context.Context, level tfsandbox.LogLevel, mess
121128
diagLevel = diag.Info
122129
}
123130

131+
if diagLevel == diag.Error && isMissingCredentialsErrorFromAWS(message) {
132+
// for AWS provider, we can detect missing credentials errors and provide a more helpful message
133+
// that is specific to Pulumi users.
134+
message = awsMissingCredentialsErrorMessage
135+
}
136+
124137
err = l.hc.Log(ctx, diagLevel, l.urn, message)
125138

126139
contract.IgnoreError(err)

tests/acc_test.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,6 @@ func TestTerraformAwsModulesVpcIntoTypeScript(t *testing.T) {
477477

478478
func TestS3BucketModSecret(t *testing.T) {
479479
// t.Parallel() - cannot use t.Parallel because the test uses SetEnv
480-
481480
localProviderBinPath := ensureCompiledProvider(t)
482481
skipLocalRunsWithoutCreds(t)
483482
testProgram := filepath.Join("testdata", "programs", "ts", "s3bucketmod")
@@ -517,6 +516,35 @@ func TestS3BucketModSecret(t *testing.T) {
517516
}
518517
}
519518

519+
func TestShowingModifiedAWSCredentialsError(t *testing.T) {
520+
skipLocalRunsWithoutCreds(t)
521+
localProviderBinPath := ensureCompiledProvider(t)
522+
523+
testProgram := filepath.Join("testdata", "programs", "ts", "s3bucketmod")
524+
localPath := opttest.LocalProviderPath("terraform-module", filepath.Dir(localProviderBinPath))
525+
526+
// disable AWS credentials to test the error message shows up
527+
integrationTest := newPulumiTest(t, testProgram, localPath,
528+
opttest.Env("AWS_ACCESS_KEY_ID", ""),
529+
opttest.Env("AWS_SECRET_ACCESS_KEY", ""),
530+
opttest.Env("AWS_SESSION_TOKEN", ""),
531+
opttest.Env("AWS_REGION", ""))
532+
533+
// Get a prefix for resource names
534+
prefix := generateTestResourcePrefix()
535+
536+
// Set prefix via config
537+
integrationTest.SetConfig(t, "prefix", prefix)
538+
539+
// Generate package
540+
//nolint:all
541+
pulumiPackageAdd(t, integrationTest, localProviderBinPath, "terraform-aws-modules/s3-bucket/aws", "4.5.0", "bucket")
542+
_, err := integrationTest.CurrentStack().Up(context.Background())
543+
assert.Error(t, err)
544+
// assert that error contains part of the modified credentials error message which is Pulumi sepcific
545+
assert.ErrorContains(t, err, "Alternatively, you can use Pulumi ESC to set up dynamic credentials with AWS OIDC")
546+
}
547+
520548
// When writing out TF files, we need to replace data that is random with a static value
521549
// so that the TF files are deterministic.
522550
func cleanRandomDataFromTerraformArtifacts(t *testing.T, tfFilesDir string, replaces map[string]string) {

0 commit comments

Comments
 (0)