From 85c5fbf4699200e498bf4716fef27a26ed0571cb Mon Sep 17 00:00:00 2001 From: Mike Grass Date: Thu, 22 Oct 2020 12:24:47 -0600 Subject: [PATCH] Improve errors for aws login with an unbound ARN (#10036) * Improve errors for aws login with an unbound ARN * Factor hasWildcardBind into its own function Co-authored-by: Calvin Leung Huang --- builtin/credential/aws/path_login.go | 34 +++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/builtin/credential/aws/path_login.go b/builtin/credential/aws/path_login.go index df99c4a35260..e030c3faae62 100644 --- a/builtin/credential/aws/path_login.go +++ b/builtin/credential/aws/path_login.go @@ -1047,18 +1047,23 @@ func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, d case !roleEntry.ResolveAWSUniqueIDs && strutil.StrListContains(roleEntry.BoundIamPrincipalARNs, canonicalArn): // check 2 passed default: // check 3 is a bit more complex, so we do it last + // only try to look up full ARNs if there's a wildcard ARN in BoundIamPrincipalIDs. + if !hasWildcardBind(roleEntry.BoundIamPrincipalARNs) { + return nil, fmt.Errorf("role %q no longer bound to ARN %q", roleName, canonicalArn) + } + fullArn := b.getCachedUserId(clientUserId) if fullArn == "" { entity, err := parseIamArn(canonicalArn) if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("error parsing ARN %q: {{err}}", canonicalArn), err) + return nil, errwrap.Wrapf(fmt.Sprintf("error parsing ARN %q when updating login for role %q: {{err}}", canonicalArn, roleName), err) } fullArn, err = b.fullArn(ctx, entity, req.Storage) if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("error looking up full ARN of entity %v: {{err}}", entity), err) + return nil, errwrap.Wrapf(fmt.Sprintf("error looking up full ARN of entity %v when updating login for role %q: {{err}}", entity, roleName), err) } if fullArn == "" { - return nil, fmt.Errorf("got empty string back when looking up full ARN of entity %v", entity) + return nil, fmt.Errorf("got empty string back when looking up full ARN of entity %v when updating login for role %q", entity, roleName) } if clientUserId != "" { b.setCachedUserId(clientUserId, fullArn) @@ -1072,7 +1077,7 @@ func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, d } } if !matchedWildcardBind { - return nil, fmt.Errorf("role no longer bound to ARN %q", canonicalArn) + return nil, fmt.Errorf("role %q no longer bound to ARN %q", roleName, canonicalArn) } } } @@ -1317,15 +1322,19 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request, case strutil.StrListContains(roleEntry.BoundIamPrincipalIDs, callerUniqueId): // check 1 passed case !roleEntry.ResolveAWSUniqueIDs && strutil.StrListContains(roleEntry.BoundIamPrincipalARNs, entity.canonicalArn()): // check 2 passed default: - // evaluate check 3 + // evaluate check 3 -- only try to look up full ARNs if there's a wildcard ARN in BoundIamPrincipalIDs. + if !hasWildcardBind(roleEntry.BoundIamPrincipalARNs) { + return logical.ErrorResponse("IAM Principal %q does not belong to the role %q", callerID.Arn, roleName), nil + } + fullArn := b.getCachedUserId(callerUniqueId) if fullArn == "" { fullArn, err = b.fullArn(ctx, entity, req.Storage) if err != nil { - return logical.ErrorResponse(fmt.Sprintf("error looking up full ARN of entity %v: %v", entity, err)), nil + return logical.ErrorResponse("error looking up full ARN of entity %v when attempting login for role %q: %v", entity, roleName, err), nil } if fullArn == "" { - return logical.ErrorResponse(fmt.Sprintf("got empty string back when looking up full ARN of entity %v", entity)), nil + return logical.ErrorResponse("got empty string back when looking up full ARN of entity %v when attempting login for role %q", entity, roleName), nil } b.setCachedUserId(callerUniqueId, fullArn) } @@ -1337,7 +1346,7 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request, } } if !matchedWildcardBind { - return logical.ErrorResponse(fmt.Sprintf("IAM Principal %q does not belong to the role %q", callerID.Arn, roleName)), nil + return logical.ErrorResponse("IAM Principal %q does not belong to the role %q", callerID.Arn, roleName), nil } } } @@ -1409,6 +1418,15 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request, }, nil } +func hasWildcardBind(boundIamPrincipalARNs []string) bool { + for _, principalARN := range boundIamPrincipalARNs { + if strings.HasSuffix(principalARN, "*") { + return true + } + } + return false +} + // Validate that the iam_request_body passed is valid for the STS request func validateLoginIamRequestBody(body string) error { qs, err := url.ParseQuery(body)