Skip to content

Commit

Permalink
resource: use sts.Creds instead of role
Browse files Browse the repository at this point in the history
In the management account if we try to assume the
OrganizationAccountAccessRole and fail we should use the default
credentials and assume they are in the management account.

The OrganizationAccountAccessRole is created by default in child
accounts, but not in the management account.
  • Loading branch information
dschofie committed May 10, 2024
1 parent 3c64ff4 commit 0626a24
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 45 deletions.
52 changes: 33 additions & 19 deletions resourceoperation/cdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/samsarahq/go/oops"
"github.com/santiago-labs/telophasecli/cmd/runner"
"github.com/santiago-labs/telophasecli/lib/awssess"
"github.com/santiago-labs/telophasecli/lib/awssts"
Expand Down Expand Up @@ -45,18 +46,18 @@ func (co *cdkOperation) ListDependents() []ResourceOperation {
func (co *cdkOperation) Call(ctx context.Context) error {
co.OutputUI.Print(fmt.Sprintf("Executing CDK stack in %s", co.Stack.Path), *co.Account)

opRole, region, err := authAWS(*co.Account, *co.Stack.RoleARN(*co.Account), co.OutputUI)
creds, region, err := authAWS(*co.Account, *co.Stack.RoleARN(*co.Account), co.OutputUI)
if err != nil {
return err
}

// We must bootstrap cdk with the account role.
bootstrapCDK := bootstrapCDK(opRole, region, *co.Account, co.Stack)
bootstrapCDK := bootstrapCDK(creds, region, *co.Account, co.Stack)
if err := co.OutputUI.RunCmd(bootstrapCDK, *co.Account); err != nil {
return err
}

synthCDK := synthCDK(opRole, *co.Account, co.Stack)
synthCDK := synthCDK(creds, *co.Account, co.Stack)
if err := co.OutputUI.RunCmd(synthCDK, *co.Account); err != nil {
return err
}
Expand All @@ -76,11 +77,11 @@ func (co *cdkOperation) Call(ctx context.Context) error {

cmd := exec.Command(localstack.CdkCmd(), cdkArgs...)
cmd.Dir = co.Stack.Path
if opRole != nil {
if creds != nil {
cmd.Env = awssts.SetEnviron(os.Environ(),
*opRole.Credentials.AccessKeyId,
*opRole.Credentials.SecretAccessKey,
*opRole.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
co.Stack.AWSRegionEnv(),
)
}
Expand All @@ -101,7 +102,7 @@ func (co *cdkOperation) ToString() string {
return ""
}

func bootstrapCDK(result *sts.AssumeRoleOutput, region string, acct resource.Account, stack resource.Stack) *exec.Cmd {
func bootstrapCDK(creds *sts.Credentials, region string, acct resource.Account, stack resource.Stack) *exec.Cmd {
cdkArgs := append([]string{
"bootstrap",
fmt.Sprintf("aws://%s/%s", acct.AccountID, region),
Expand All @@ -111,42 +112,52 @@ func bootstrapCDK(result *sts.AssumeRoleOutput, region string, acct resource.Acc

cmd := exec.Command(localstack.CdkCmd(), cdkArgs...)
cmd.Dir = stack.Path
if result != nil {
if creds != nil {
cmd.Env = awssts.SetEnviron(os.Environ(),
*result.Credentials.AccessKeyId,
*result.Credentials.SecretAccessKey,
*result.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
stack.AWSRegionEnv(),
)
}

return cmd
}

func synthCDK(result *sts.AssumeRoleOutput, acct resource.Account, stack resource.Stack) *exec.Cmd {
func synthCDK(creds *sts.Credentials, acct resource.Account, stack resource.Stack) *exec.Cmd {
cdkArgs := append(
[]string{"synth"},
cdkDefaultArgs(acct, stack)...,
)

cmd := exec.Command(localstack.CdkCmd(), cdkArgs...)
cmd.Dir = stack.Path
if result != nil {
if creds != nil {
cmd.Env = awssts.SetEnviron(os.Environ(),
*result.Credentials.AccessKeyId,
*result.Credentials.SecretAccessKey,
*result.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
stack.AWSRegionEnv(),
)
}

return cmd
}

func authAWS(acct resource.Account, arn string, consoleUI runner.ConsoleUI) (*sts.AssumeRoleOutput, string, error) {
func authAWS(acct resource.Account, arn string, consoleUI runner.ConsoleUI) (*sts.Credentials, string, error) {

var svc *sts.STS
sess := session.Must(awssess.DefaultSession())
svc = sts.New(sess)
// If we are in the management account we the OrganizationAccountAccessRole does not exist so fallback to the current credentials.
if acct.ManagementAccount {
output, err := svc.GetSessionToken(&sts.GetSessionTokenInput{})
if err != nil {
return nil, "", oops.Wrapf(err, "GetSessionToken")
}
// TODO: figure out region for management account
return output.Credentials, "us-east-1", nil
}

consoleUI.Print(fmt.Sprintf("Assuming role: %s", arn), acct)
input := &sts.AssumeRoleInput{
Expand All @@ -155,7 +166,10 @@ func authAWS(acct resource.Account, arn string, consoleUI runner.ConsoleUI) (*st
}

role, err := awssess.AssumeRole(svc, input)
return role, *sess.Config.Region, err
if err != nil {
return nil, "", oops.Wrapf(err, "AssumeRole")
}
return role.Credentials, *sess.Config.Region, nil
}

func cdkDefaultArgs(acct resource.Account, stack resource.Stack) []string {
Expand Down
20 changes: 10 additions & 10 deletions resourceoperation/scp.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ func (so *scpOperation) ListDependents() []ResourceOperation {
func (so *scpOperation) Call(ctx context.Context) error {
so.OutputUI.Print(fmt.Sprintf("Executing SCP Terraform stack in %s", so.Stack.Path), *so.MgmtAcct)

var acctRole *sts.AssumeRoleOutput
var creds *sts.Credentials
if so.MgmtAcct.AssumeRoleName != "" {
var err error
acctRole, _, err = authAWS(*so.MgmtAcct, so.MgmtAcct.AssumeRoleARN(), so.OutputUI)
creds, _, err = authAWS(*so.MgmtAcct, so.MgmtAcct.AssumeRoleARN(), so.OutputUI)
if err != nil {
return err
}
Expand All @@ -121,11 +121,11 @@ func (so *scpOperation) Call(ctx context.Context) error {
}

if initTFCmd != nil {
if acctRole != nil {
if creds != nil {
initTFCmd.Env = awssts.SetEnviron(os.Environ(),
*acctRole.Credentials.AccessKeyId,
*acctRole.Credentials.SecretAccessKey,
*acctRole.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
// SCPs can't have regions
nil,
)
Expand All @@ -150,11 +150,11 @@ func (so *scpOperation) Call(ctx context.Context) error {
cmd := exec.Command(localstack.TfCmd(), args...)
cmd.Dir = workingPath

if acctRole != nil {
if creds != nil {
cmd.Env = awssts.SetEnviron(os.Environ(),
*acctRole.Credentials.AccessKeyId,
*acctRole.Credentials.SecretAccessKey,
*acctRole.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
// SCPs don't have regions
nil,
)
Expand Down
32 changes: 16 additions & 16 deletions resourceoperation/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,29 @@ func (to *tfOperation) ListDependents() []ResourceOperation {
func (to *tfOperation) Call(ctx context.Context) error {
to.OutputUI.Print(fmt.Sprintf("Executing Terraform stack in %s", to.Stack.Path), *to.Account)

var stackRole *sts.AssumeRoleOutput
var creds *sts.Credentials
var assumeRoleErr error
if to.Account.AccountID != "" {
if roleArn := to.Stack.RoleARN(*to.Account); roleArn != nil {
stackRole, _, assumeRoleErr = authAWS(*to.Account, *roleArn, to.OutputUI)
creds, _, assumeRoleErr = authAWS(*to.Account, *roleArn, to.OutputUI)
} else {
stackRole, _, assumeRoleErr = authAWS(*to.Account, to.Account.AssumeRoleARN(), to.OutputUI)
creds, _, assumeRoleErr = authAWS(*to.Account, to.Account.AssumeRoleARN(), to.OutputUI)
}

if assumeRoleErr != nil {
return assumeRoleErr
}
}

initTFCmd := to.initTf(stackRole)
initTFCmd := to.initTf(creds)
if initTFCmd != nil {
if err := to.OutputUI.RunCmd(initTFCmd, *to.Account); err != nil {
return err
}
}

// Set workspace if we are using it.
setWorkspace, err := to.setWorkspace(stackRole)
setWorkspace, err := to.setWorkspace(creds)
if err != nil {
return err
}
Expand All @@ -93,9 +93,9 @@ func (to *tfOperation) Call(ctx context.Context) error {
cmd.Dir = workingPath

cmd.Env = awssts.SetEnviron(os.Environ(),
*stackRole.Credentials.AccessKeyId,
*stackRole.Credentials.SecretAccessKey,
*stackRole.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
to.Stack.AWSRegionEnv(),
)

Expand All @@ -112,7 +112,7 @@ func (to *tfOperation) Call(ctx context.Context) error {
return nil
}

func (to *tfOperation) initTf(role *sts.AssumeRoleOutput) *exec.Cmd {
func (to *tfOperation) initTf(creds *sts.Credentials) *exec.Cmd {
workingPath := terraform.TmpPath(*to.Account, to.Stack.Path)
terraformDir := filepath.Join(workingPath, ".terraform")
if terraformDir == "" || !strings.Contains(terraformDir, "telophasedirs") {
Expand Down Expand Up @@ -140,9 +140,9 @@ func (to *tfOperation) initTf(role *sts.AssumeRoleOutput) *exec.Cmd {
cmd.Dir = workingPath

cmd.Env = awssts.SetEnviron(os.Environ(),
*role.Credentials.AccessKeyId,
*role.Credentials.SecretAccessKey,
*role.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
to.Stack.AWSRegionEnv(),
)

Expand All @@ -168,7 +168,7 @@ func replaceVals(workspace, AccountID, Region string) (string, error) {
return currentContent, nil
}

func (to *tfOperation) setWorkspace(role *sts.AssumeRoleOutput) (*exec.Cmd, error) {
func (to *tfOperation) setWorkspace(creds *sts.Credentials) (*exec.Cmd, error) {
if !to.Stack.WorkspaceEnabled() {
return nil, nil
}
Expand All @@ -184,9 +184,9 @@ func (to *tfOperation) setWorkspace(role *sts.AssumeRoleOutput) (*exec.Cmd, erro
cmd.Dir = workingPath

cmd.Env = awssts.SetEnviron(os.Environ(),
*role.Credentials.AccessKeyId,
*role.Credentials.SecretAccessKey,
*role.Credentials.SessionToken,
*creds.AccessKeyId,
*creds.SecretAccessKey,
*creds.SessionToken,
to.Stack.AWSRegionEnv(),
)

Expand Down

0 comments on commit 0626a24

Please sign in to comment.