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`.
@@ -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)
- 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()
+ glog.V(5).Infof("Querying AWS STS for profile metadata")
+ identity, err := ctx.STS().GetCallerIdentity(nil)
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.
