Skip to content

Commit

Permalink
add new built-in function get_aws_account_aliases(), fix #2483 (#3607)
Browse files Browse the repository at this point in the history
  • Loading branch information
wakeful authored Dec 3, 2024
1 parent ba1e4b5 commit cfe02c5
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 0 deletions.
26 changes: 26 additions & 0 deletions awshelper/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions config/config_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions docs/_docs/04_reference/built-in-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/get-aws-account-alias/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
variable "account_alias" {
type = string
}

output "account_alias" {
value = var.account_alias
}
3 changes: 3 additions & 0 deletions test/fixtures/get-aws-account-alias/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
inputs = {
account_alias = get_aws_account_alias()
}
41 changes: 41 additions & 0 deletions test/integration_aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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()

Expand Down

0 comments on commit cfe02c5

Please sign in to comment.