Use STS instead of IAM to identify AWS account

The IAM GetUser operation fails when invoked with an assumed IAM
role.  Instead, use STS `GetCallerIdentity`.
This commit is contained in:
Luke Hoban 2017-07-07 14:02:37 -07:00
parent ea0461dadb
commit 48ffd280a6

View file

@ -16,12 +16,11 @@ import (
"github.com/aws/aws-sdk-go/service/lambda"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/pulumi/lumi/pkg/resource/provider"
"github.com/pulumi/lumi/pkg/util/contract"
"github.com/pulumi/lumi/lib/aws/provider/arn"
)
// Context represents state shared amongst all parties in this process. In particular, it wraps an AWS session
@ -42,6 +41,7 @@ type Context struct {
lambda *lambda.Lambda
s3 *s3.S3
sns *sns.SNS
sts *sts.STS
}
const regionConfig = "aws:config:region"
@ -73,26 +73,17 @@ func New(host *provider.HostClient) (*Context, error) {
// Allocate the context early since we are about to use it to access the IAM service. Its usage is inherently
// limited until we have finished construction (in other words, completion of the present function).
ctx := &Context{sess: sess}
// Query the IAM service to fetch the IAM user and role information.
glog.V(5).Infof("Querying AWS IAM service for profile metadata")
iaminfo, err := ctx.IAM().GetUser(nil)
glog.V(5).Infof("Querying AWS STS for profile metadata")
identity, err := ctx.STS().GetCallerIdentity(nil)
if err != nil {
return nil, err
}
contract.Assert(iaminfo != nil)
contract.Assert(iaminfo.User != nil)
contract.Assert(iaminfo.User.Arn != nil)
userARN := arn.ARN(*iaminfo.User.Arn)
// Parse and store the ARN information on the context for convenient access.
parsedARN, err := userARN.Parse()
if err != nil {
return nil, err
}
ctx.accountID = parsedARN.AccountID
ctx.accountRole = parsedARN.Resource
glog.V(7).Infof("AWS IAM profile ARN received: %v (id=%v role=%v)", userARN, ctx.accountID, ctx.accountRole)
contract.Assert(identity != nil)
ctx.accountID = aws.StringValue(identity.Account)
ctx.accountRole = aws.StringValue(identity.Arn)
user := aws.StringValue(identity.UserId)
glog.V(7).Infof("AWS STS identity received: %v (id=%v role=%v)", user, ctx.accountID, ctx.accountRole)
return ctx, nil
}
@ -172,6 +163,14 @@ func (ctx *Context) SNS() *sns.SNS {
return ctx.sns
}
func (ctx *Context) STS() *sts.STS {
contract.Assert(ctx.sess != nil)
if ctx.sts == nil {
ctx.sts = sts.New(ctx.sess)
}
return ctx.sts
}
// Request manufactures a standard Golang context object for a request within this overall AWS context.
func (ctx *Context) Request() context.Context {
// IDEA: unify this with the gRPC context; this will be easier once gRPC moves to the standard Golang context.