From 651fe288b5074e4c7e4ebdd8d48709ea83c0e657 Mon Sep 17 00:00:00 2001 From: Muse Mulatu Date: Tue, 4 Mar 2025 15:01:47 -0700 Subject: [PATCH 1/2] feat: detokenize principals ARN --- go.mod | 2 ++ go.sum | 2 ++ internal/aws/sts.go | 43 ++++++++++++++++++++++++++++++- internal/controller/cluster.go | 6 +++++ pkg/providerConfigs/detokenize.go | 1 + pkg/providerConfigs/types.go | 1 + 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 987dd666..43ef911e 100644 --- a/go.mod +++ b/go.mod @@ -88,6 +88,8 @@ require ( sigs.k8s.io/yaml v1.4.0 ) +require github.com/YakDriver/regexache v0.24.0 // indirect + require ( cel.dev/expr v0.16.1 // indirect cloud.google.com/go v0.116.0 // indirect diff --git a/go.sum b/go.sum index 4eff917a..efaabf21 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/YakDriver/regexache v0.24.0 h1:zUKaixelkswzdqsqPc2sveiV//Mi/msJn0teG8zBDiA= +github.com/YakDriver/regexache v0.24.0/go.mod h1:awcd8uBj614F3ScW06JqlfSGqq2/7vdJHy+RiKzVC+g= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= diff --git a/internal/aws/sts.go b/internal/aws/sts.go index b63ec97f..85843524 100644 --- a/internal/aws/sts.go +++ b/internal/aws/sts.go @@ -9,7 +9,12 @@ package aws import ( "context" "fmt" + "strings" + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/sts" ) @@ -22,5 +27,41 @@ func (conf *Configuration) GetCallerIdentity() (*sts.GetCallerIdentityOutput, er if err != nil { fmt.Printf("error: could not get caller identity %s", err) } - return iamCaller, nil + + return iamCaller, err +} + +// sourceIAMRoleARN Given an STS ARN returns the ARN for the source IAM role +// or returns User's arn +func (conf *Configuration) sourceIAMRoleARN(rawARN string) (string, error) { + iamClient := iam.NewFromConfig(conf.Config) + + parsedARN, err := arn.Parse(rawARN) + + if err != nil { + return "", err + } + + reAssume := regexache.MustCompile(`^assumed-role/.{1,}/.{2,}`) + + if !reAssume.MatchString(parsedARN.Resource) || parsedARN.Service != "sts" { + return rawARN, nil + } + + parts := strings.Split(parsedARN.Resource, "/") + + if len(parts) < 3 { + return "", nil + } + + iamInput := &iam.GetRoleInput{ + RoleName: aws.String(parts[len(parts)-2]), + } + + output, err := iamClient.GetRole(context.Background(), iamInput) + if err != nil { + return "", err + } + + return *output.Role.Arn, nil } diff --git a/internal/controller/cluster.go b/internal/controller/cluster.go index fae3f732..3d913466 100644 --- a/internal/controller/cluster.go +++ b/internal/controller/cluster.go @@ -248,6 +248,11 @@ func (clctrl *ClusterController) CreateTokens(kind string) interface{} { return fmt.Errorf("error getting AWS caller identity while creating tokens: %w", err) } + roleArn, err := clctrl.AwsClient.sourceIAMRoleARN(*iamCaller.Arn) + if err != nil { + return fmt.Errorf("error getting principals ARN: %w", err) + } + // to be added to general tokens struct gitopsTemplateTokens.AwsIamArnAccountRoot = fmt.Sprintf("arn:aws:iam::%s:root", *iamCaller.Account) gitopsTemplateTokens.AwsNodeCapacityType = "ON_DEMAND" // todo adopt cli flag @@ -256,6 +261,7 @@ func (clctrl *ClusterController) CreateTokens(kind string) interface{} { gitopsTemplateTokens.KubefirstArtifactsBucket = clctrl.KubefirstArtifactsBucketName gitopsTemplateTokens.AtlantisWebhookURL = clctrl.AtlantisWebhookURL gitopsTemplateTokens.AMIType = clctrl.AMIType + gitopsTemplateTokens.AwsCallerArn = roleArn if clctrl.ECR { gitopsTemplateTokens.ContainerRegistryURL = fmt.Sprintf("%s.dkr.ecr.%s.amazonaws.com", *iamCaller.Account, clctrl.CloudRegion) diff --git a/pkg/providerConfigs/detokenize.go b/pkg/providerConfigs/detokenize.go index 7bf9d873..5cee7d3e 100644 --- a/pkg/providerConfigs/detokenize.go +++ b/pkg/providerConfigs/detokenize.go @@ -87,6 +87,7 @@ func detokenizeGitops(tokens *GitopsDirectoryValues, gitProtocol string, useClou newContents = strings.ReplaceAll(newContents, "", tokens.AwsAccountID) newContents = strings.ReplaceAll(newContents, "", tokens.AwsIamArnAccountRoot) newContents = strings.ReplaceAll(newContents, "", tokens.AwsNodeCapacityType) + newContents = strings.ReplaceAll(newContents, "", tokens.AwsCallerArn) // Azure azureDNSZoneName := "" diff --git a/pkg/providerConfigs/types.go b/pkg/providerConfigs/types.go index 9bcc0221..ec80ac0d 100644 --- a/pkg/providerConfigs/types.go +++ b/pkg/providerConfigs/types.go @@ -51,6 +51,7 @@ type GitopsDirectoryValues struct { AwsNodeCapacityType string AwsAccountID string AMIType string + AwsCallerArn string AzureStorageResourceGroup string AzureStorageContainerName string From e240b69bff0a4208098c13d589e2c5b3d589a11d Mon Sep 17 00:00:00 2001 From: Muse Mulatu Date: Tue, 4 Mar 2025 15:15:42 -0700 Subject: [PATCH 2/2] fix: export method --- internal/aws/sts.go | 4 ++-- internal/controller/cluster.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/aws/sts.go b/internal/aws/sts.go index 85843524..5f0faf3a 100644 --- a/internal/aws/sts.go +++ b/internal/aws/sts.go @@ -31,9 +31,9 @@ func (conf *Configuration) GetCallerIdentity() (*sts.GetCallerIdentityOutput, er return iamCaller, err } -// sourceIAMRoleARN Given an STS ARN returns the ARN for the source IAM role +// SourceIAMRoleARN Given an STS ARN returns the ARN for the source IAM role // or returns User's arn -func (conf *Configuration) sourceIAMRoleARN(rawARN string) (string, error) { +func (conf *Configuration) SourceIAMRoleARN(rawARN string) (string, error) { iamClient := iam.NewFromConfig(conf.Config) parsedARN, err := arn.Parse(rawARN) diff --git a/internal/controller/cluster.go b/internal/controller/cluster.go index 3d913466..2dc5a4c3 100644 --- a/internal/controller/cluster.go +++ b/internal/controller/cluster.go @@ -248,7 +248,7 @@ func (clctrl *ClusterController) CreateTokens(kind string) interface{} { return fmt.Errorf("error getting AWS caller identity while creating tokens: %w", err) } - roleArn, err := clctrl.AwsClient.sourceIAMRoleARN(*iamCaller.Arn) + roleArn, err := clctrl.AwsClient.SourceIAMRoleARN(*iamCaller.Arn) if err != nil { return fmt.Errorf("error getting principals ARN: %w", err) }