Skip to content

Commit

Permalink
Ensure we validate credentials correctly
Browse files Browse the repository at this point in the history
Fixes: #1995

Currently the creds validation is broken:
[![asciicast](https://asciinema.org/a/AgIZGKgVnFEejf2wKIegTECrm.svg)](https://asciinema.org/a/AgIZGKgVnFEejf2wKIegTECrm)

New code:

With AWS_PROFILE:
[![asciicast](https://asciinema.org/a/qSdDAZCtgnDWiCBH2MBG5cQ8I.svg)](https://asciinema.org/a/qSdDAZCtgnDWiCBH2MBG5cQ8I)

With default creds:
[![asciicast](https://asciinema.org/a/A4v7yF9VHq1Mr0hayfkabLNBm.svg)](https://asciinema.org/a/A4v7yF9VHq1Mr0hayfkabLNBm)

With Environment Vars for AWS_ACCESS_KEY_ID && AWS_SECRET_ACCESS_KEY
[![asciica
  • Loading branch information
stack72 committed Jun 14, 2022
1 parent 01a5162 commit 8d6e63b
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 63 deletions.
4 changes: 2 additions & 2 deletions provider/cmd/pulumi-resource-aws/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"skipCredentialsValidation": {
"type": "boolean",
"description": "Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS\navailable/implemented.\n",
"default": true
"default": false
},
"skipGetEc2Platforms": {
"type": "boolean",
Expand Down Expand Up @@ -211399,7 +211399,7 @@
"skipCredentialsValidation": {
"type": "boolean",
"description": "Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS\navailable/implemented.\n",
"default": true
"default": false
},
"skipGetEc2Platforms": {
"type": "boolean",
Expand Down
128 changes: 76 additions & 52 deletions provider/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
package provider

import (
"context"
"fmt"
"math/rand"
"os"
"path/filepath"
"strings"
"unicode"

"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
awsbase "github.com/hashicorp/aws-sdk-go-base/v2"
awsShim "github.com/hashicorp/terraform-provider-aws/shim"
"github.com/mitchellh/go-homedir"
"github.com/pulumi/pulumi-aws/provider/v5/pkg/version"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
Expand Down Expand Up @@ -270,55 +274,78 @@ func stringRef(s string) *string {
// configuration subset of `github.com/terraform-providers/terraform-provider-aws/aws.providerConfigure`. We do this
// before passing control to the TF provider to ensure we can report actionable errors.
func preConfigureCallback(vars resource.PropertyMap, c shim.ResourceConfig) error {
// Don't event attempt any credentialsValidation at all while we get to the bottom of
// https://github.com/pulumi/pulumi-aws/issues/199
return nil
var skipCredentialsValidation bool
if val, ok := vars["skipCredentialsValidation"]; ok {
if val.IsBool() {
skipCredentialsValidation = val.BoolValue()
}
}

// if we skipCredentialsValidation then we don't need to do anything in
// preConfigureCallback as this is an explicit operation
if skipCredentialsValidation {
return nil
}

config := &awsbase.Config{
AccessKey: stringValue(vars, "accessKey", []string{"AWS_ACCESS_KEY_ID"}),
SecretKey: stringValue(vars, "secretKey", []string{"AWS_SECRET_ACCESS_KEY"}),
Profile: stringValue(vars, "profile", []string{"AWS_PROFILE"}),
Token: stringValue(vars, "token", []string{"AWS_SESSION_TOKEN"}),
Region: stringValue(vars, "region", []string{"AWS_REGION", "AWS_DEFAULT_REGION"}),
}

if details, ok := vars["assumeRole"]; ok {
assumeRoleDetails := resource.NewPropertyMap(details)
assumeRole := awsbase.AssumeRole{
RoleARN: stringValue(assumeRoleDetails, "roleArn", []string{}),
ExternalID: stringValue(assumeRoleDetails, "externalId", []string{}),
Policy: stringValue(assumeRoleDetails, "policy", []string{}),
SessionName: stringValue(assumeRoleDetails, "sessionName", []string{}),
}
config.AssumeRole = &assumeRole
}

// By default `skipMetadataApiCheck` is true for Pulumi to speed operations
// if we want to authenticate against the AWS API Metadata Service then the user
// will specify that skipMetadataApiCheck: false
// therefore, if we have skipMetadataApiCheck false, then we are enabling the imds client
config.EC2MetadataServiceEnableState = imds.ClientDisabled
if val, ok := vars["skipMetadataApiCheck"]; ok {
if val.IsBool() && !val.BoolValue() {
config.EC2MetadataServiceEnableState = imds.ClientEnabled
}
}

//var skipCredentialsValidation bool
//if val, ok := vars["skipCredentialsValidation"]; ok {
// if val.IsBool() {
// skipCredentialsValidation = val.BoolValue()
// }
//}
//
//// if we skipCredentialsValidation then we don't need to do anything in
//// preConfigureCallback as this is an explict operation
//if skipCredentialsValidation {
// return nil
//}
//
//config := &awsbase.Config{
// AccessKey: stringValue(vars, "accessKey", []string{"AWS_ACCESS_KEY_ID"}),
// SecretKey: stringValue(vars, "secretKey", []string{"AWS_SECRET_ACCESS_KEY"}),
// Profile: stringValue(vars, "profile", []string{"AWS_PROFILE"}),
// Token: stringValue(vars, "token", []string{"AWS_SESSION_TOKEN"}),
// Region: stringValue(vars, "region", []string{"AWS_REGION", "AWS_DEFAULT_REGION"}),
//}
//
//// By default `skipMetadataApiCheck` is true for Pulumi to speed operations
//// if we want to authenticate against the AWS API Metadata Service then the user
//// will specify that skipMetadataApiCheck: false
//// therefore, if we have skipMetadataApiCheck false, then we are enabling the imds client
//config.EC2MetadataServiceEnableState = imds.ClientDisabled
//if val, ok := vars["skipMetadataApiCheck"]; ok {
// if val.IsBool() && !val.BoolValue() {
// config.EC2MetadataServiceEnableState = imds.ClientEnabled
// }
//}
//
//sharedCredentialsFile := stringValue(vars, "sharedCredentialsFile", []string{"AWS_SHARED_CREDENTIALS_FILE"})
//credsPath, err := homedir.Expand(sharedCredentialsFile)
//if err != nil {
// return err
//}
//config.SharedCredentialsFiles = []string{credsPath}
//
//if _, err := awsbase.GetAwsConfig(context.Background(), config); err != nil {
// return fmt.Errorf("unable to validate AWS AccessKeyID and/or SecretAccessKey " +
// "- see https://pulumi.io/install/aws.html for details on configuration")
//}
//
//return nil
// lastly let's set the sharedCreds and sharedConfig file. If these are not found then let's default to the
// locations that AWS cli will store these values.
sharedCredentialsFile := stringValue(vars, "sharedCredentialsFile", []string{"AWS_SHARED_CREDENTIALS_FILE"})
if sharedCredentialsFile == "" {
sharedCredentialsFile = "~/.aws/credentials"
}
credsPath, err := homedir.Expand(sharedCredentialsFile)
if err != nil {
return err
}

sharedConfigFile := stringValue(vars, "sharedConfigFile", []string{"AWS_SHARED_CONFIG_FILE"})
if sharedConfigFile == "" {
sharedConfigFile = "~/.aws/config"
}
configPath, err := homedir.Expand(sharedConfigFile)
if err != nil {
return err
}

config.SharedCredentialsFiles = []string{credsPath}
config.SharedConfigFiles = []string{configPath}

if _, err := awsbase.GetAwsConfig(context.Background(), config); err != nil {
return fmt.Errorf("unable to validate AWS credentials " +
"- see https://pulumi.io/install/aws.html for details on configuration")
}

return nil
}

// managedByPulumi is a default used for some managed resources, in the absence of something more meaningful.
Expand Down Expand Up @@ -365,10 +392,7 @@ func Provider() tfbridge.ProviderInfo {
// be in a situation where a user can be waiting for a resource
// creation timeout (default up to 30mins) to find out that they
// have not got valid credentials

// this is temporarily skipped while we look at the cause of
// https://github.com/pulumi/pulumi-aws/issues/1995
Value: true,
Value: false,
},
},
"skip_metadata_api_check": {
Expand Down
2 changes: 1 addition & 1 deletion sdk/dotnet/Config/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public static ImmutableArray<string> SharedCredentialsFiles
set => _sharedCredentialsFiles.Set(value);
}

private static readonly __Value<bool?> _skipCredentialsValidation = new __Value<bool?>(() => __config.GetBoolean("skipCredentialsValidation") ?? true);
private static readonly __Value<bool?> _skipCredentialsValidation = new __Value<bool?>(() => __config.GetBoolean("skipCredentialsValidation") ?? false);
/// <summary>
/// Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS
/// available/implemented.
Expand Down
2 changes: 1 addition & 1 deletion sdk/dotnet/Provider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public InputList<string> SharedCredentialsFiles
public ProviderArgs()
{
Region = Utilities.GetEnv("AWS_REGION", "AWS_DEFAULT_REGION");
SkipCredentialsValidation = true;
SkipCredentialsValidation = false;
SkipGetEc2Platforms = true;
SkipMetadataApiCheck = true;
SkipRegionValidation = true;
Expand Down
2 changes: 1 addition & 1 deletion sdk/go/aws/config/config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/go/aws/provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/nodejs/config/vars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ Object.defineProperty(exports, "sharedCredentialsFiles", {
export declare const skipCredentialsValidation: boolean;
Object.defineProperty(exports, "skipCredentialsValidation", {
get() {
return __config.getObject<boolean>("skipCredentialsValidation") ?? true;
return __config.getObject<boolean>("skipCredentialsValidation") ?? false;
},
enumerable: true,
});
Expand Down
2 changes: 1 addition & 1 deletion sdk/nodejs/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class Provider extends pulumi.ProviderResource {
resourceInputs["sharedConfigFiles"] = pulumi.output(args ? args.sharedConfigFiles : undefined).apply(JSON.stringify);
resourceInputs["sharedCredentialsFile"] = args ? args.sharedCredentialsFile : undefined;
resourceInputs["sharedCredentialsFiles"] = pulumi.output(args ? args.sharedCredentialsFiles : undefined).apply(JSON.stringify);
resourceInputs["skipCredentialsValidation"] = pulumi.output((args ? args.skipCredentialsValidation : undefined) ?? true).apply(JSON.stringify);
resourceInputs["skipCredentialsValidation"] = pulumi.output((args ? args.skipCredentialsValidation : undefined) ?? false).apply(JSON.stringify);
resourceInputs["skipGetEc2Platforms"] = pulumi.output((args ? args.skipGetEc2Platforms : undefined) ?? true).apply(JSON.stringify);
resourceInputs["skipMetadataApiCheck"] = pulumi.output((args ? args.skipMetadataApiCheck : undefined) ?? true).apply(JSON.stringify);
resourceInputs["skipRegionValidation"] = pulumi.output((args ? args.skipRegionValidation : undefined) ?? true).apply(JSON.stringify);
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/pulumi_aws/config/vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def skip_credentials_validation(self) -> bool:
Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS
available/implemented.
"""
return __config__.get_bool('skipCredentialsValidation') or True
return __config__.get_bool('skipCredentialsValidation') or False

@property
def skip_get_ec2_platforms(self) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions sdk/python/pulumi_aws/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def __init__(__self__, *,
if shared_credentials_files is not None:
pulumi.set(__self__, "shared_credentials_files", shared_credentials_files)
if skip_credentials_validation is None:
skip_credentials_validation = True
skip_credentials_validation = False
if skip_credentials_validation is not None:
pulumi.set(__self__, "skip_credentials_validation", skip_credentials_validation)
if skip_get_ec2_platforms is None:
Expand Down Expand Up @@ -714,7 +714,7 @@ def _internal_init(__self__,
__props__.__dict__["shared_credentials_file"] = shared_credentials_file
__props__.__dict__["shared_credentials_files"] = pulumi.Output.from_input(shared_credentials_files).apply(pulumi.runtime.to_json) if shared_credentials_files is not None else None
if skip_credentials_validation is None:
skip_credentials_validation = True
skip_credentials_validation = False
__props__.__dict__["skip_credentials_validation"] = pulumi.Output.from_input(skip_credentials_validation).apply(pulumi.runtime.to_json) if skip_credentials_validation is not None else None
if skip_get_ec2_platforms is None:
skip_get_ec2_platforms = True
Expand Down

0 comments on commit 8d6e63b

Please sign in to comment.