aws-sdk-go-v2
aws-sdk-go-v2 copied to clipboard
Add credential provider for role chaining
Describe the feature
Add a CredentialProvider that implements role chaining: generating ephemeral credentials via sts using a series of iam roles.
Use Case
From the docs:
Role chaining is when you use a role to assume a second role through the AWS CLI or API. For example, RoleA has permission to assume RoleB. You can enable User1 to assume RoleA by using their long-term user credentials in the AssumeRole API operation. This returns RoleA short-term credentials. With role chaining, you can use RoleA's short-term credentials to enable User1 to assume RoleB.
Proposed Solution
The implementation might be a new CredentialProvider, e.g. AssumeChainedRoleProvider, that repeatedly invokes AssumeRoleProvider over a series of iam roles.
Other Information
No response
Acknowledgements
- [X] I may be able to implement this feature request
- [ ] This feature might incur a breaking change
AWS Go SDK V2 Module Versions Used
latest
Go version used
latest
Hi @jmcarp ,
Thanks for the feature request. The Go SDK already supports credential role chaining implicitly. You need to setup your .aws/config file the same way suggested in the docs you have linked.
Are you asking about an explicit credential provider that implements this? Or were you unaware that we implicitly support this?
Thank you! Ran~
I'm one of the :+1:s .
We run our services stateless-ly - without a config - and we chain roles programattically. For us, a service has role from web identity, we use that to assume a different role, and keep assuming until we're at the correct role. We have some abstractions to help with that but it's a sufficiently common use-case that I think it could be valuable to have the SDK provide it out-of-the-box.
I'm not sure what that looks like exactly. I'm not particularly keen on our abstraction or I would share it.
Hi @JTarasovic ,
I think an explicit role chain provider is a reasonable request but in the spirit of transparency I'll say that it's likely that this wont get implemented anytime soon. The team is prioritizing bug fixes, and feature parity at the moment.
I will obviously keep this open because it had a good amount of engagement, and when we get additional bandwidth this will get addressed.
Thanks again, Ran~
This could probably be cleaned up a bit if it were a part of the SDK (e.g., have direct access to the provider options instead of having to rely on the NewAssumeRoleProvider function), but it solves our use cases.
type Role struct {
Arn string
Options []func(*stscreds.AssumeRoleOptions)
}
func NewAssumeRoleChainProvider(cfg aws.Config, roles ...*Role) (*stscreds.AssumeRoleProvider, error) {
var chain []*stscreds.AssumeRoleProvider
for idx, r := range roles {
if idx == 0 {
p := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), r.Arn, r.Options...)
chain = append(chain, p)
continue
}
p := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg, func(o *sts.Options) {
o.Credentials = aws.NewCredentialsCache(chain[idx-1])
}), r.Arn, r.Options...)
chain = append(chain, p)
}
return chain[len(chain)-1], nil
}
Example usage:
func main() {
// get background context
ctx := context.Background()
// load aws config
cfg, err := config.LoadDefaultConfig(ctx, func(o *config.LoadOptions) error {
o.Region = "us-east-1"
return nil
})
if err != nil {
log.Fatalln(err.Error())
}
provider, err := NewAssumeRoleChainProvider(cfg,
&Role{
Arn: "arn:aws:iam::123456789012:role/one",
},
&Role{
Arn: "arn:aws:iam::123456789012:role/two",
Options: []func(*stscreds.AssumeRoleOptions){
func(o *stscreds.AssumeRoleOptions) {
o.ExternalID = aws.String("ext-id-1234")
},
},
},
&Role{
Arn: "arn:aws:iam::123456789012:role/three",
},
)
if err != nil {
log.Fatalln(err)
}
// attach chained credential provider to config
cfg.Credentials = provider
// do something only three can do...
client := ec2.NewFromConfig(cfg)
resp, err := client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{})
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Reservations)
}