Skip to content

Commit

Permalink
Read all AWS env vars (#874)
Browse files Browse the repository at this point in the history
For both programmatic access, and for pre configuration, we must read in all the appropriate env vars.

Fixes #252
  • Loading branch information
lukehoban committed Feb 12, 2020
1 parent 5d1471a commit 20bc79d
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 32 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -2,7 +2,7 @@ CHANGELOG
=========

## HEAD (Unreleased)
_(none)_
* Read standard AWS environment variables for configuration

---

Expand Down
42 changes: 35 additions & 7 deletions resources.go
Expand Up @@ -18,6 +18,7 @@ import (
"errors"
"fmt"
"math/rand"
"os"
"strings"
"unicode"

Expand Down Expand Up @@ -201,11 +202,17 @@ func boolRef(b bool) *bool {
}

// stringValue gets a string value from a property map if present, else ""
func stringValue(vars resource.PropertyMap, prop resource.PropertyKey) string {
func stringValue(vars resource.PropertyMap, prop resource.PropertyKey, envs []string) string {
val, ok := vars[prop]
if ok && val.IsString() {
return val.StringValue()
}
for _, env := range envs {
val, ok := os.LookupEnv(env)
if ok {
return val
}
}
return ""
}

Expand All @@ -214,14 +221,15 @@ func stringValue(vars resource.PropertyMap, prop resource.PropertyKey) string {
// before passing control to the TF provider to ensure we can report actionable errors.
func preConfigureCallback(vars resource.PropertyMap, c *terraform.ResourceConfig) error {
config := &awsbase.Config{
AccessKey: stringValue(vars, "accessKey"),
SecretKey: stringValue(vars, "secretKey"),
Profile: stringValue(vars, "profile"),
Token: stringValue(vars, "token"),
Region: stringValue(vars, "region"),
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"}),
}

credsPath, err := homedir.Expand(stringValue(vars, "sharedCredentialsFile"))
sharedCredentialsFile := stringValue(vars, "sharedCredentialsFile", []string{"AWS_SHARED_CREDENTIALS_FILE"})
credsPath, err := homedir.Expand(sharedCredentialsFile)
if err != nil {
return err
}
Expand Down Expand Up @@ -251,6 +259,16 @@ func Provider() tfbridge.ProviderInfo {
Repository: "https://github.com/pulumi/pulumi-aws",
Version: version.Version,
Config: map[string]*tfbridge.SchemaInfo{
"access_key": {
Default: &tfbridge.DefaultInfo{
EnvVars: []string{"AWS_ACCESS_KEY_ID"},
},
},
"secret_key": {
Default: &tfbridge.DefaultInfo{
EnvVars: []string{"AWS_SECRET_ACCESS_KEY"},
},
},
"region": {
Type: awsTypeNoFile("region", "Region"),
Default: &tfbridge.DefaultInfo{
Expand All @@ -262,6 +280,16 @@ func Provider() tfbridge.ProviderInfo {
EnvVars: []string{"AWS_PROFILE"},
},
},
"token": {
Default: &tfbridge.DefaultInfo{
EnvVars: []string{"AWS_SESSION_TOKEN"},
},
},
"shared_credentials_file": {
Default: &tfbridge.DefaultInfo{
EnvVars: []string{"AWS_SHARED_CREDENTIALS_FILE"},
},
},
},
PreConfigureCallback: preConfigureCallback,
Resources: map[string]*tfbridge.ResourceInfo{
Expand Down
8 changes: 4 additions & 4 deletions sdk/dotnet/Config/Config.cs
Expand Up @@ -13,7 +13,7 @@ public static class Config
/// The access key for API operations. You can retrieve this from the 'Security & Credentials' section of
/// the AWS console.
/// </summary>
public static string? AccessKey { get; set; } = __config.Get("accessKey");
public static string? AccessKey { get; set; } = __config.Get("accessKey") ?? Utilities.GetEnv("AWS_ACCESS_KEY_ID");

public static ImmutableArray<string> AllowedAccountIds { get; set; } = __config.GetObject<ImmutableArray<string>>("allowedAccountIds");

Expand Down Expand Up @@ -65,12 +65,12 @@ public static class Config
/// The secret key for API operations. You can retrieve this from the 'Security &amp; Credentials' section of
/// the AWS console.
/// </summary>
public static string? SecretKey { get; set; } = __config.Get("secretKey");
public static string? SecretKey { get; set; } = __config.Get("secretKey") ?? Utilities.GetEnv("AWS_SECRET_ACCESS_KEY");

/// <summary>
/// The path to the shared credentials file. If not set this defaults to ~/.aws/credentials.
/// </summary>
public static string? SharedCredentialsFile { get; set; } = __config.Get("sharedCredentialsFile");
public static string? SharedCredentialsFile { get; set; } = __config.Get("sharedCredentialsFile") ?? Utilities.GetEnv("AWS_SHARED_CREDENTIALS_FILE");

/// <summary>
/// Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS
Expand Down Expand Up @@ -101,7 +101,7 @@ public static class Config
/// <summary>
/// session token. A session token is only required if you are using temporary security credentials.
/// </summary>
public static string? Token { get; set; } = __config.Get("token");
public static string? Token { get; set; } = __config.Get("token") ?? Utilities.GetEnv("AWS_SESSION_TOKEN");

}
namespace ConfigTypes
Expand Down
4 changes: 4 additions & 0 deletions sdk/dotnet/Provider.cs
Expand Up @@ -188,8 +188,12 @@ public InputList<string> IgnoreTags

public ProviderArgs()
{
AccessKey = Utilities.GetEnv("AWS_ACCESS_KEY_ID");
Profile = Utilities.GetEnv("AWS_PROFILE");
Region = Utilities.GetEnv("AWS_REGION", "AWS_DEFAULT_REGION");
SecretKey = Utilities.GetEnv("AWS_SECRET_ACCESS_KEY");
SharedCredentialsFile = Utilities.GetEnv("AWS_SHARED_CREDENTIALS_FILE");
Token = Utilities.GetEnv("AWS_SESSION_TOKEN");
}
}

Expand Down
28 changes: 20 additions & 8 deletions sdk/go/aws/config/config.go
Expand Up @@ -11,8 +11,11 @@ import (

// The access key for API operations. You can retrieve this from the 'Security & Credentials' section of the AWS console.
func GetAccessKey(ctx *pulumi.Context) string {
return config.Get(ctx, "aws:accessKey")
}
v, err := config.Try(ctx, "aws:accessKey")
if err == nil {
return v
}
return getEnvOrDefault("", nil, "AWS_ACCESS_KEY_ID").(string)}
func GetAllowedAccountIds(ctx *pulumi.Context) string {
return config.Get(ctx, "aws:allowedAccountIds")
}
Expand Down Expand Up @@ -63,12 +66,18 @@ func GetS3ForcePathStyle(ctx *pulumi.Context) bool {
}
// The secret key for API operations. You can retrieve this from the 'Security & Credentials' section of the AWS console.
func GetSecretKey(ctx *pulumi.Context) string {
return config.Get(ctx, "aws:secretKey")
}
v, err := config.Try(ctx, "aws:secretKey")
if err == nil {
return v
}
return getEnvOrDefault("", nil, "AWS_SECRET_ACCESS_KEY").(string)}
// The path to the shared credentials file. If not set this defaults to ~/.aws/credentials.
func GetSharedCredentialsFile(ctx *pulumi.Context) string {
return config.Get(ctx, "aws:sharedCredentialsFile")
}
v, err := config.Try(ctx, "aws:sharedCredentialsFile")
if err == nil {
return v
}
return getEnvOrDefault("", nil, "AWS_SHARED_CREDENTIALS_FILE").(string)}
// Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS
// available/implemented.
func GetSkipCredentialsValidation(ctx *pulumi.Context) bool {
Expand All @@ -92,5 +101,8 @@ func GetSkipRequestingAccountId(ctx *pulumi.Context) bool {
}
// session token. A session token is only required if you are using temporary security credentials.
func GetToken(ctx *pulumi.Context) string {
return config.Get(ctx, "aws:token")
}
v, err := config.Try(ctx, "aws:token")
if err == nil {
return v
}
return getEnvOrDefault("", nil, "AWS_SESSION_TOKEN").(string)}
12 changes: 12 additions & 0 deletions sdk/go/aws/provider.go
Expand Up @@ -27,12 +27,24 @@ func NewProvider(ctx *pulumi.Context,
if args == nil {
args = &ProviderArgs{}
}
if args.AccessKey == nil {
args.AccessKey = pulumi.StringPtr(getEnvOrDefault("", nil, "AWS_ACCESS_KEY_ID").(string))
}
if args.Profile == nil {
args.Profile = pulumi.StringPtr(getEnvOrDefault("", nil, "AWS_PROFILE").(string))
}
if args.Region == nil {
args.Region = pulumi.StringPtr(getEnvOrDefault("", nil, "AWS_REGION", "AWS_DEFAULT_REGION").(string))
}
if args.SecretKey == nil {
args.SecretKey = pulumi.StringPtr(getEnvOrDefault("", nil, "AWS_SECRET_ACCESS_KEY").(string))
}
if args.SharedCredentialsFile == nil {
args.SharedCredentialsFile = pulumi.StringPtr(getEnvOrDefault("", nil, "AWS_SHARED_CREDENTIALS_FILE").(string))
}
if args.Token == nil {
args.Token = pulumi.StringPtr(getEnvOrDefault("", nil, "AWS_SESSION_TOKEN").(string))
}
var resource Provider
err := ctx.RegisterResource("pulumi:providers:aws", name, args, &resource, opts...)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions sdk/nodejs/config/vars.ts
Expand Up @@ -11,7 +11,7 @@ let __config = new pulumi.Config("aws");
/**
* The access key for API operations. You can retrieve this from the 'Security & Credentials' section of the AWS console.
*/
export let accessKey: string | undefined = __config.get("accessKey");
export let accessKey: string | undefined = __config.get("accessKey") || utilities.getEnv("AWS_ACCESS_KEY_ID");
export let allowedAccountIds: string[] | undefined = __config.getObject<string[]>("allowedAccountIds");
export let assumeRole: { externalId?: string, policy?: string, roleArn?: string, sessionName?: string } | undefined = __config.getObject<{ externalId?: string, policy?: string, roleArn?: string, sessionName?: string }>("assumeRole");
export let endpoints: { accessanalyzer?: string, acm?: string, acmpca?: string, amplify?: string, apigateway?: string, applicationautoscaling?: string, applicationinsights?: string, appmesh?: string, appstream?: string, appsync?: string, athena?: string, autoscaling?: string, autoscalingplans?: string, backup?: string, batch?: string, budgets?: string, cloud9?: string, cloudformation?: string, cloudfront?: string, cloudhsm?: string, cloudsearch?: string, cloudtrail?: string, cloudwatch?: string, cloudwatchevents?: string, cloudwatchlogs?: string, codebuild?: string, codecommit?: string, codedeploy?: string, codepipeline?: string, cognitoidentity?: string, cognitoidp?: string, configservice?: string, cur?: string, dataexchange?: string, datapipeline?: string, datasync?: string, dax?: string, devicefarm?: string, directconnect?: string, dlm?: string, dms?: string, docdb?: string, ds?: string, dynamodb?: string, ec2?: string, ecr?: string, ecs?: string, efs?: string, eks?: string, elasticache?: string, elasticbeanstalk?: string, elastictranscoder?: string, elb?: string, emr?: string, es?: string, firehose?: string, fms?: string, forecast?: string, fsx?: string, gamelift?: string, glacier?: string, globalaccelerator?: string, glue?: string, greengrass?: string, guardduty?: string, iam?: string, imagebuilder?: string, inspector?: string, iot?: string, iotanalytics?: string, iotevents?: string, kafka?: string, kinesis?: string, kinesisAnalytics?: string, kinesisanalytics?: string, kinesisvideo?: string, kms?: string, lakeformation?: string, lambda?: string, lexmodels?: string, licensemanager?: string, lightsail?: string, macie?: string, managedblockchain?: string, marketplacecatalog?: string, mediaconnect?: string, mediaconvert?: string, medialive?: string, mediapackage?: string, mediastore?: string, mediastoredata?: string, mq?: string, neptune?: string, opsworks?: string, organizations?: string, personalize?: string, pinpoint?: string, pricing?: string, qldb?: string, quicksight?: string, r53?: string, ram?: string, rds?: string, redshift?: string, resourcegroups?: string, route53?: string, route53resolver?: string, s3?: string, s3control?: string, sagemaker?: string, sdb?: string, secretsmanager?: string, securityhub?: string, serverlessrepo?: string, servicecatalog?: string, servicediscovery?: string, servicequotas?: string, ses?: string, shield?: string, sns?: string, sqs?: string, ssm?: string, stepfunctions?: string, storagegateway?: string, sts?: string, swf?: string, transfer?: string, waf?: string, wafregional?: string, wafv2?: string, worklink?: string, workspaces?: string, xray?: string }[] | undefined = __config.getObject<{ accessanalyzer?: string, acm?: string, acmpca?: string, amplify?: string, apigateway?: string, applicationautoscaling?: string, applicationinsights?: string, appmesh?: string, appstream?: string, appsync?: string, athena?: string, autoscaling?: string, autoscalingplans?: string, backup?: string, batch?: string, budgets?: string, cloud9?: string, cloudformation?: string, cloudfront?: string, cloudhsm?: string, cloudsearch?: string, cloudtrail?: string, cloudwatch?: string, cloudwatchevents?: string, cloudwatchlogs?: string, codebuild?: string, codecommit?: string, codedeploy?: string, codepipeline?: string, cognitoidentity?: string, cognitoidp?: string, configservice?: string, cur?: string, dataexchange?: string, datapipeline?: string, datasync?: string, dax?: string, devicefarm?: string, directconnect?: string, dlm?: string, dms?: string, docdb?: string, ds?: string, dynamodb?: string, ec2?: string, ecr?: string, ecs?: string, efs?: string, eks?: string, elasticache?: string, elasticbeanstalk?: string, elastictranscoder?: string, elb?: string, emr?: string, es?: string, firehose?: string, fms?: string, forecast?: string, fsx?: string, gamelift?: string, glacier?: string, globalaccelerator?: string, glue?: string, greengrass?: string, guardduty?: string, iam?: string, imagebuilder?: string, inspector?: string, iot?: string, iotanalytics?: string, iotevents?: string, kafka?: string, kinesis?: string, kinesisAnalytics?: string, kinesisanalytics?: string, kinesisvideo?: string, kms?: string, lakeformation?: string, lambda?: string, lexmodels?: string, licensemanager?: string, lightsail?: string, macie?: string, managedblockchain?: string, marketplacecatalog?: string, mediaconnect?: string, mediaconvert?: string, medialive?: string, mediapackage?: string, mediastore?: string, mediastoredata?: string, mq?: string, neptune?: string, opsworks?: string, organizations?: string, personalize?: string, pinpoint?: string, pricing?: string, qldb?: string, quicksight?: string, r53?: string, ram?: string, rds?: string, redshift?: string, resourcegroups?: string, route53?: string, route53resolver?: string, s3?: string, s3control?: string, sagemaker?: string, sdb?: string, secretsmanager?: string, securityhub?: string, serverlessrepo?: string, servicecatalog?: string, servicediscovery?: string, servicequotas?: string, ses?: string, shield?: string, sns?: string, sqs?: string, ssm?: string, stepfunctions?: string, storagegateway?: string, sts?: string, swf?: string, transfer?: string, waf?: string, wafregional?: string, wafv2?: string, worklink?: string, workspaces?: string, xray?: string }[]>("endpoints");
Expand Down Expand Up @@ -49,11 +49,11 @@ export let s3ForcePathStyle: boolean | undefined = __config.getObject<boolean>("
/**
* The secret key for API operations. You can retrieve this from the 'Security & Credentials' section of the AWS console.
*/
export let secretKey: string | undefined = __config.get("secretKey");
export let secretKey: string | undefined = __config.get("secretKey") || utilities.getEnv("AWS_SECRET_ACCESS_KEY");
/**
* The path to the shared credentials file. If not set this defaults to ~/.aws/credentials.
*/
export let sharedCredentialsFile: string | undefined = __config.get("sharedCredentialsFile");
export let sharedCredentialsFile: string | undefined = __config.get("sharedCredentialsFile") || utilities.getEnv("AWS_SHARED_CREDENTIALS_FILE");
/**
* Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS
* available/implemented.
Expand All @@ -76,4 +76,4 @@ export let skipRequestingAccountId: boolean | undefined = __config.getObject<boo
/**
* session token. A session token is only required if you are using temporary security credentials.
*/
export let token: string | undefined = __config.get("token");
export let token: string | undefined = __config.get("token") || utilities.getEnv("AWS_SESSION_TOKEN");
8 changes: 4 additions & 4 deletions sdk/nodejs/provider.ts
Expand Up @@ -42,7 +42,7 @@ export class Provider extends pulumi.ProviderResource {
constructor(name: string, args?: ProviderArgs, opts?: pulumi.ResourceOptions) {
let inputs: pulumi.Inputs = {};
{
inputs["accessKey"] = args ? args.accessKey : undefined;
inputs["accessKey"] = (args ? args.accessKey : undefined) || utilities.getEnv("AWS_ACCESS_KEY_ID");
inputs["allowedAccountIds"] = pulumi.output(args ? args.allowedAccountIds : undefined).apply(JSON.stringify);
inputs["assumeRole"] = pulumi.output(args ? args.assumeRole : undefined).apply(JSON.stringify);
inputs["endpoints"] = pulumi.output(args ? args.endpoints : undefined).apply(JSON.stringify);
Expand All @@ -54,14 +54,14 @@ export class Provider extends pulumi.ProviderResource {
inputs["profile"] = (args ? args.profile : undefined) || utilities.getEnv("AWS_PROFILE");
inputs["region"] = (args ? args.region : undefined) || utilities.getEnv("AWS_REGION", "AWS_DEFAULT_REGION");
inputs["s3ForcePathStyle"] = pulumi.output(args ? args.s3ForcePathStyle : undefined).apply(JSON.stringify);
inputs["secretKey"] = args ? args.secretKey : undefined;
inputs["sharedCredentialsFile"] = args ? args.sharedCredentialsFile : undefined;
inputs["secretKey"] = (args ? args.secretKey : undefined) || utilities.getEnv("AWS_SECRET_ACCESS_KEY");
inputs["sharedCredentialsFile"] = (args ? args.sharedCredentialsFile : undefined) || utilities.getEnv("AWS_SHARED_CREDENTIALS_FILE");
inputs["skipCredentialsValidation"] = pulumi.output(args ? args.skipCredentialsValidation : undefined).apply(JSON.stringify);
inputs["skipGetEc2Platforms"] = pulumi.output(args ? args.skipGetEc2Platforms : undefined).apply(JSON.stringify);
inputs["skipMetadataApiCheck"] = pulumi.output(args ? args.skipMetadataApiCheck : undefined).apply(JSON.stringify);
inputs["skipRegionValidation"] = pulumi.output(args ? args.skipRegionValidation : undefined).apply(JSON.stringify);
inputs["skipRequestingAccountId"] = pulumi.output(args ? args.skipRequestingAccountId : undefined).apply(JSON.stringify);
inputs["token"] = args ? args.token : undefined;
inputs["token"] = (args ? args.token : undefined) || utilities.getEnv("AWS_SESSION_TOKEN");
}
if (!opts) {
opts = {}
Expand Down
8 changes: 4 additions & 4 deletions sdk/python/pulumi_aws/config/vars.py
Expand Up @@ -11,7 +11,7 @@

__config__ = pulumi.Config('aws')

access_key = __config__.get('accessKey')
access_key = __config__.get('accessKey') or utilities.get_env('AWS_ACCESS_KEY_ID')
"""
The access key for API operations. You can retrieve this from the 'Security & Credentials' section of the AWS console.
"""
Expand Down Expand Up @@ -61,12 +61,12 @@
Specific to the Amazon S3 service.
"""

secret_key = __config__.get('secretKey')
secret_key = __config__.get('secretKey') or utilities.get_env('AWS_SECRET_ACCESS_KEY')
"""
The secret key for API operations. You can retrieve this from the 'Security & Credentials' section of the AWS console.
"""

shared_credentials_file = __config__.get('sharedCredentialsFile')
shared_credentials_file = __config__.get('sharedCredentialsFile') or utilities.get_env('AWS_SHARED_CREDENTIALS_FILE')
"""
The path to the shared credentials file. If not set this defaults to ~/.aws/credentials.
"""
Expand Down Expand Up @@ -95,7 +95,7 @@
Skip requesting the account ID. Used for AWS API implementations that do not have IAM/STS API and/or metadata API.
"""

token = __config__.get('token')
token = __config__.get('token') or utilities.get_env('AWS_SESSION_TOKEN')
"""
session token. A session token is only required if you are using temporary security credentials.
"""
Expand Down

0 comments on commit 20bc79d

Please sign in to comment.