diff --git a/awshelper/config.go b/awshelper/config.go index 334656cea..03019bba3 100644 --- a/awshelper/config.go +++ b/awshelper/config.go @@ -8,6 +8,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/iam" "github.com/gruntwork-io/go-commons/version" "github.com/aws/aws-sdk-go/aws" @@ -357,6 +358,31 @@ func GetAWSPartition(config *AwsSessionConfig, terragruntOptions *options.Terrag return arn.Partition, nil } +// GetAWSAccountAlias gets the AWS account Alias of the current session configuration, +// if there is no alias an empty string is return. +func GetAWSAccountAlias(config *AwsSessionConfig, terragruntOptions *options.TerragruntOptions) (string, error) { + sess, err := CreateAwsSession(config, terragruntOptions) + if err != nil { + return "", errors.New(err) + } + + aliases, err := iam.New(sess).ListAccountAliases(nil) + if err != nil { + return "", errors.New(err) + } + + if len(aliases.AccountAliases) != 1 { // AWS supports only one alias per account https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccountAliases.html + return "", nil + } + + alias := aliases.AccountAliases[0] + if alias == nil { + return "", errors.Errorf("expected AWS account alias, got nil") + } + + return *alias, nil +} + // GetAWSAccountID gets the AWS account ID of the current session configuration. func GetAWSAccountID(config *AwsSessionConfig, terragruntOptions *options.TerragruntOptions) (string, error) { identity, err := GetAWSCallerIdentity(config, terragruntOptions) diff --git a/config/config_helpers.go b/config/config_helpers.go index 666217b26..1d1bf40fb 100644 --- a/config/config_helpers.go +++ b/config/config_helpers.go @@ -52,6 +52,7 @@ const ( FuncNameGetTerraformCommand = "get_terraform_command" FuncNameGetTerraformCLIArgs = "get_terraform_cli_args" FuncNameGetParentTerragruntDir = "get_parent_terragrunt_dir" + FuncNameGetAWSAccountAlias = "get_aws_account_alias" FuncNameGetAWSAccountID = "get_aws_account_id" FuncNameGetAWSCallerIdentityArn = "get_aws_caller_identity_arn" FuncNameGetAWSCallerIdentityUserID = "get_aws_caller_identity_user_id" @@ -156,6 +157,7 @@ func createTerragruntEvalContext(ctx *ParsingContext, configPath string) (*hcl.E FuncNameGetTerraformCommand: wrapVoidToStringAsFuncImpl(ctx, getTerraformCommand), FuncNameGetTerraformCLIArgs: wrapVoidToStringSliceAsFuncImpl(ctx, getTerraformCliArgs), FuncNameGetParentTerragruntDir: wrapStringSliceToStringAsFuncImpl(ctx, GetParentTerragruntDir), + FuncNameGetAWSAccountAlias: wrapVoidToStringAsFuncImpl(ctx, getAWSAccountAlias), FuncNameGetAWSAccountID: wrapVoidToStringAsFuncImpl(ctx, getAWSAccountID), FuncNameGetAWSCallerIdentityArn: wrapVoidToStringAsFuncImpl(ctx, getAWSCallerIdentityARN), FuncNameGetAWSCallerIdentityUserID: wrapVoidToStringAsFuncImpl(ctx, getAWSCallerIdentityUserID), @@ -589,6 +591,16 @@ func getDefaultRetryableErrors(ctx *ParsingContext) ([]string, error) { return options.DefaultRetryableErrors, nil } +// Return the AWS account alias +func getAWSAccountAlias(ctx *ParsingContext) (string, error) { + accountAlias, err := awshelper.GetAWSAccountAlias(nil, ctx.TerragruntOptions) + if err == nil { + return accountAlias, nil + } + + return "", err +} + // Return the AWS account id associated to the current set of credentials func getAWSAccountID(ctx *ParsingContext) (string, error) { accountID, err := awshelper.GetAWSAccountID(nil, ctx.TerragruntOptions) diff --git a/docs/_docs/04_reference/built-in-functions.md b/docs/_docs/04_reference/built-in-functions.md index 6d09017fb..e16fc436a 100644 --- a/docs/_docs/04_reference/built-in-functions.md +++ b/docs/_docs/04_reference/built-in-functions.md @@ -29,6 +29,7 @@ Terragrunt allows you to use built-in functions anywhere in `terragrunt.hcl`, ju - [get\_terraform\_commands\_that\_need\_input](#get_terraform_commands_that_need_input) - [get\_terraform\_commands\_that\_need\_locking](#get_terraform_commands_that_need_locking) - [get\_terraform\_commands\_that\_need\_parallelism](#get_terraform_commands_that_need_parallelism) +- [get\_aws\_account\_alias](#get_aws_account_alias) - [get\_aws\_account\_id](#get_aws_account_id) - [get\_aws\_caller\_identity\_arn](#get_aws_caller_identity_arn) - [get\_terraform\_command](#get_terraform_command) @@ -553,6 +554,18 @@ terraform { } ``` +## get_aws_account_alias + +`get_aws_account_alias()` returns the AWS account alias associated with the current set of credentials. If the alias cannot be found, it will return an empty string. Example: + +```hcl +inputs = { + account_alias = get_aws_account_alias() +} +``` + +**Note:** value returned by `get_aws_account_alias()` can change during parsing of HCL code, for example after evaluation of `iam_role` attribute. + ## get_aws_account_id `get_aws_account_id()` returns the AWS account id associated with the current set of credentials. Example: diff --git a/test/fixtures/get-aws-account-alias/main.tf b/test/fixtures/get-aws-account-alias/main.tf new file mode 100644 index 000000000..5233593bc --- /dev/null +++ b/test/fixtures/get-aws-account-alias/main.tf @@ -0,0 +1,7 @@ +variable "account_alias" { + type = string +} + +output "account_alias" { + value = var.account_alias +} diff --git a/test/fixtures/get-aws-account-alias/terragrunt.hcl b/test/fixtures/get-aws-account-alias/terragrunt.hcl new file mode 100644 index 000000000..eb53aff62 --- /dev/null +++ b/test/fixtures/get-aws-account-alias/terragrunt.hcl @@ -0,0 +1,3 @@ +inputs = { + account_alias = get_aws_account_alias() +} diff --git a/test/integration_aws_test.go b/test/integration_aws_test.go index b3b49b9dd..4cb994fae 100644 --- a/test/integration_aws_test.go +++ b/test/integration_aws_test.go @@ -17,6 +17,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/service/sts" "github.com/gruntwork-io/go-commons/files" @@ -35,6 +36,7 @@ import ( const ( testFixtureAwsProviderPatch = "fixtures/aws-provider-patch" + testFixtureAwsAccountAlias = "fixtures/get-aws-account-alias" testFixtureAwsGetCallerIdentity = "fixtures/get-aws-caller-identity" testFixtureS3Errors = "fixtures/s3-errors/" testFixtureAssumeRole = "fixtures/assume-role/external-id" @@ -469,6 +471,45 @@ func TestAwsLocalWithBackend(t *testing.T) { helpers.RunTerragrunt(t, "terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-working-dir "+rootPath) } +func TestAwsGetAccountAliasFunctions(t *testing.T) { + t.Parallel() + + helpers.CleanupTerraformFolder(t, testFixtureAwsAccountAlias) + tmpEnvPath := helpers.CopyEnvironment(t, testFixtureAwsAccountAlias) + rootPath := util.JoinPath(tmpEnvPath, testFixtureAwsAccountAlias) + + helpers.RunTerragrunt(t, "terragrunt apply-all --terragrunt-non-interactive --terragrunt-working-dir "+rootPath) + + // verify expected outputs are not empty + stdout := bytes.Buffer{} + stderr := bytes.Buffer{} + + require.NoError( + t, + helpers.RunTerragruntCommand(t, "terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir "+rootPath, &stdout, &stderr), + ) + + // Get values from STS + sess, err := session.NewSession() + if err != nil { + t.Fatalf("Error while creating AWS session: %v", err) + } + + aliases, err := iam.New(sess).ListAccountAliases(nil) + if err != nil { + t.Fatalf("Error while getting AWS account aliases: %v", err) + } + + alias := "" + if len(aliases.AccountAliases) == 1 { + alias = *aliases.AccountAliases[0] + } + + outputs := map[string]helpers.TerraformOutput{} + require.NoError(t, json.Unmarshal(stdout.Bytes(), &outputs)) + assert.Equal(t, outputs["account_alias"].Value, alias) +} + func TestAwsGetCallerIdentityFunctions(t *testing.T) { t.Parallel()