aws-sdk-go-v2 icon indicating copy to clipboard operation
aws-sdk-go-v2 copied to clipboard

Better AssumeRole example

Open kaihendry opened this issue 4 years ago • 7 comments

Is your feature request related to a problem? Please describe.

On the cli, it's aws sts assume-role --role-arn "arn:aws:iam::XYZ:role/ViewLogsPlease" --role-session-name ViewOne

And then you awkwardly need to setup AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN, however it's less awkward than wading through wierd non-sensical documentation like https://aws.github.io/aws-sdk-go-v2/docs/code-examples/sts/assumerole/

Describe the solution you'd like

Clear working instructions like

   creds := stscreds.NewAssumeRoleProvider(stsclient, "arn:aws:iam::XYZ:role/ViewLogsPlease", func(p *stscreds.AssumeRoleOpti  ons) {
          p.RoleSessionName = "ViewLogsPlease"
      })
      // Magic sauce to get the current role
      cfg.Credentials = aws.NewCredentialsCache(creds)

Describe alternatives you've considered Maybe I should go back to v1, because v2 hasn't made the cfg any easier!

Additional context

Additionally I went down the rabbit hole of assuming that something like:

  cfg, err := config.LoadDefaultConfig(context.TODO(),
          config.WithSharedConfigProfile("mine"),
          config.WithAssumeRoleCredentialOptions(func(o *stscreds.AssumeRoleOptions) {
           o.RoleARN = "arn:aws:iam::XYZ:role/ViewLogsPlease"
           }),
      )

It doesn't work, and I have no idea why. github.com/aws/aws-sdk-go-v2 v1.8.0

kaihendry avatar Aug 17 '21 08:08 kaihendry

Thanks for reaching out @kaihendry . To help clarify the issue, could you provide if your SharedConfigProfile in this example has assume role configured in it?

As documented at https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#WithAssumeRoleCredentialOptions

WithAssumeRoleCredentialOptions is a helper function to construct functional options that sets a function to use stscreds.AssumeRoleOptions on config's LoadOptions. If assume role credentials options is set to nil, the assume role credentials value will be ignored. If multiple WithAssumeRoleCredentialOptions calls are made, the last call overrides the previous call values.

The WithAssumeRoleCredentialOptions works similar to how you are configuring p.RoleSessionName = "ViewLogsPlease" in your first code snippet.

In your example - if no assume role was present in "mine" shared config profile, the WithAssumeRoleCredentialOptions will not be invoked.

We will update our example docs to reflect this requirement.

skotambkar avatar Aug 18 '21 18:08 skotambkar

I think the confusion here might be that @kaihendry is looking for programmatic role assumption. But what WithAssumeRoleCredentialOptions provides is configuring an assumed-role profile from configuration. That looks like the following in your ~/.aws/config:

# this is a pre-existing profile you already have
[profile profile-to-call-assume-role-with]
# maybe it's IAM User credentials
# or AWS SSO config
# or whatever else you may have

[profile view-logs]
role_arn = arn:aws:iam::XYZ:role/ViewLogsPlease
# optional: role_session_name = MyRoleSessionName

source_profile = profile-to-call-assume-role-with
# or instead of source_profile, you can tell it to
# use external credentials. one of:
# credential_source = Environment
# credential_source = Ec2InstanceMetadata
# credential_source = EcsContainer

With this config, you can reference the view-logs profile like any other. WithAssumeRoleCredentialOptions lets you modify the parameters of the AssumeRole call that is caused by this profile, but can't make it use an assumed role where none is present in the config file.

This is in contrast to the JavaScript SDK, which provides ChainableTemporaryCredentials as a way to configure the SDK with a role programmatically. For boto3, I had to make a library to accomplish this.

So, hopefully the above ~/.aws/config profile option accomplishes your need, but a separate issue for programmatic role assumption seems worth opening? This would probably be a new Config type that has a role ARN and base config?

func NewAssumeRoleConfig(ctx context.Context, baseCfg aws.Config, roleARN string, v func(*stscreds.AssumeRoleOptions)) (cfg aws.Config, err error)

benkehoe avatar Oct 09 '21 21:10 benkehoe

this example is very good : https://flowerinthenight.com/blog/2021/04/30/authenticate-aws-sdk-golang-v2

petitout avatar Jan 11 '22 23:01 petitout

assumecnf, _ := config.LoadDefaultConfig(...)
stsclient := sts.NewFromConfig(assumecnf)
cnf, _ := config.LoadDefaultConfig(
	ctx, config.WithRegion("{aws-region}"),
	config.WithCredentialsProvider(aws.NewCredentialsCache(
		stscredsv2.NewAssumeRoleProvider(
			stsclient,
			"{rolearn-to-assume}",
		)),
	),
)
client := s3.NewFromConfig(cnf)
res, _ := client.GetObject(ctx, &s3.GetObjectInput{
	Bucket: awsv2.String("{some-bucket}"),
	Key:    awsv2.String("{some-key}"),
})```

petitout avatar Jan 11 '22 23:01 petitout

Came here to post a similar issue - I think the docs could be improved in this case (specifically this one: https://aws.github.io/aws-sdk-go-v2/docs/code-examples/sts/assumerole/) to show the use of the AssumeRole credentials as opposed to stopping at getting the role assumed. I also stumbled across the example above and that seems to work, but it would be good to see a working example with best practice code from AWS itself.

rayterrill avatar Mar 03 '22 18:03 rayterrill

This seems like the best, simplest example I've seen for AssumeRole: https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds#hdr-Assume_Role

rayterrill avatar Mar 03 '22 21:03 rayterrill

Assuming role without 'stscreds' (only using 'sts' and 'sts/types') and static credentials:

import (
    "context"
    "log"
    "strconv"
    "time"
    "math/rand"
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/ec2"
    "github.com/aws/aws-sdk-go-v2/sts"
    stsTypes "github.com/aws/aws-sdk-go-v2/sts/types"
)

// Create config & sts client with source account
cfg, err := config.LoadDefaultConfig (ctx, config.WithRegion(region), config.WithSharedConfigProfile(profileName))
if err != nil {
    log.Fatalf("unable to load shared profile for sts client config, %v", err)
}
sourceAccount := sts.NewFromConfig(cfg)

// Assume target role and store credentials
rand.Seed(time.Now().UnixNano())
response, err := sourceAccount.AssumeRole(ctx, &sts.AssumeRoleInput{
    RoleArn: aws.String("arn:aws:iam::ACCOUNT_NUM:role/ROLE_NAME),
    RoleSessionName: aws.String("some-identifier-" + strconv.Itoa(10000 + rand.Intn(25000))),
}
if err != nil {
    log.Fatalf("unable to assume target role, %v", err)
}
var assumedRoleCreds *stsTypes.Credentials = response.Credentials

// Create config with target service client, using assumed role
cfg, err = config.LoadDefaultConfig(ctx, config.WithRegion(region), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(*assumedRoleCreds.AccessKeyId, *assumedRoleCreds.SecretAccessKey, *assumedRoleCreds.SessionToken)))
if err != nil {
    log.Fatalf("unable to load static credentials for service client config, %v", err)
}

// Use it 
ec2.NewFromConfig(cfg)

reference: https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/#static-credentials

nckrse avatar Sep 12 '22 13:09 nckrse

Since I see many comments here with good examples I feel confident we can close this issue. If this is not sufficient please open a new issue.

Thanks, Ran~

RanVaknin avatar Nov 07 '22 19:11 RanVaknin

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Nov 07 '22 19:11 github-actions[bot]