diff --git a/builtin/credential/aws/path_login.go b/builtin/credential/aws/path_login.go index de642ed6f759..7c31cfb3bb5a 100644 --- a/builtin/credential/aws/path_login.go +++ b/builtin/credential/aws/path_login.go @@ -836,6 +836,11 @@ func (b *backend) pathLoginUpdateEc2(ctx context.Context, req *logical.Request, Alias: &logical.Alias{ Name: identityAlias, }, + InternalData: map[string]interface{}{ + "instance_id": identityDocParsed.InstanceID, + "region": identityDocParsed.Region, + "account_id": identityDocParsed.AccountID, + }, } roleEntry.PopulateTokenAuth(auth) if err := identityConfigEntry.EC2AuthMetadataHandler.PopulateDesiredMetadata(auth, map[string]string{ @@ -957,9 +962,9 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data } func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { - canonicalArn := req.Auth.Metadata["canonical_arn"] - if canonicalArn == "" { - return nil, fmt.Errorf("unable to retrieve canonical ARN from metadata during renewal") + canonicalArn, err := getMetadataValue(req.Auth, "canonical_arn") + if err != nil { + return nil, err } roleName := "" @@ -990,16 +995,19 @@ func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, d // renew existing tokens. if roleEntry.InferredEntityType != "" { if roleEntry.InferredEntityType == ec2EntityType { - instanceID, ok := req.Auth.Metadata["inferred_entity_id"] - if !ok { - return nil, fmt.Errorf("no inferred entity ID in auth metadata") + instanceID, err := getMetadataValue(req.Auth, "inferred_entity_id") + if err != nil { + return nil, err } - instanceRegion, ok := req.Auth.Metadata["inferred_aws_region"] - if !ok { - return nil, fmt.Errorf("no inferred AWS region in auth metadata") + instanceRegion, err := getMetadataValue(req.Auth, "inferred_aws_region") + if err != nil { + return nil, err } - _, err := b.validateInstance(ctx, req.Storage, instanceID, instanceRegion, req.Auth.Metadata["account_id"]) + accountID, err := getMetadataValue(req.Auth, "account_id") if err != nil { + b.Logger().Debug("account_id not present during iam renewal attempt, continuing to attempt validation") + } + if _, err := b.validateInstance(ctx, req.Storage, instanceID, instanceRegion, accountID); err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("failed to verify instance ID %q: {{err}}", instanceID), err) } } else { @@ -1021,9 +1029,9 @@ func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, d // implies that roleEntry.ResolveAWSUniqueIDs is true) // 2: roleEntry.ResolveAWSUniqueIDs is false and canonical_arn is in roleEntry.BoundIamPrincipalARNs // 3: Full ARN matches one of the wildcard globs in roleEntry.BoundIamPrincipalARNs - clientUserId, ok := req.Auth.Metadata["client_user_id"] + clientUserId, err := getMetadataValue(req.Auth, "client_user_id") switch { - case ok && strutil.StrListContains(roleEntry.BoundIamPrincipalIDs, clientUserId): // check 1 passed + case err == nil && strutil.StrListContains(roleEntry.BoundIamPrincipalIDs, clientUserId): // check 1 passed case !roleEntry.ResolveAWSUniqueIDs && strutil.StrListContains(roleEntry.BoundIamPrincipalARNs, canonicalArn): // check 2 passed default: // check 3 is a bit more complex, so we do it last @@ -1064,28 +1072,22 @@ func (b *backend) pathLoginRenewIam(ctx context.Context, req *logical.Request, d return resp, nil } -func (b *backend) pathLoginRenewEc2(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { - instanceID := req.Auth.Metadata["instance_id"] - if instanceID == "" { - return nil, fmt.Errorf("unable to fetch instance ID from metadata during renewal") +func (b *backend) pathLoginRenewEc2(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) { + instanceID, err := getMetadataValue(req.Auth, "instance_id") + if err != nil { + return nil, err } - - region := req.Auth.Metadata["region"] - if region == "" { - return nil, fmt.Errorf("unable to fetch region from metadata during renewal") + region, err := getMetadataValue(req.Auth, "region") + if err != nil { + return nil, err } - - // Ensure backwards compatibility for older clients without account_id saved in metadata - accountID, ok := req.Auth.Metadata["account_id"] - if ok { - if accountID == "" { - return nil, fmt.Errorf("unable to fetch account_id from metadata during renewal") - } + accountID, err := getMetadataValue(req.Auth, "account_id") + if err != nil { + b.Logger().Debug("account_id not present during ec2 renewal attempt, continuing to attempt validation") } // Cross check that the instance is still in 'running' state - _, err := b.validateInstance(ctx, req.Storage, instanceID, region, accountID) - if err != nil { + if _, err := b.validateInstance(ctx, req.Storage, instanceID, region, accountID); err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("failed to verify instance ID %q: {{err}}", instanceID), err) } @@ -1350,8 +1352,13 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request, "role_id": roleEntry.RoleID, }, InternalData: map[string]interface{}{ - "role_name": roleName, - "role_id": roleEntry.RoleID, + "role_name": roleName, + "role_id": roleEntry.RoleID, + "canonical_arn": entity.canonicalArn(), + "client_user_id": callerUniqueId, + "inferred_entity_id": inferredEntityID, + "inferred_aws_region": roleEntry.InferredAWSRegion, + "account_id": entity.AccountNumber, }, DisplayName: entity.FriendlyName, Alias: &logical.Alias{ @@ -1686,6 +1693,23 @@ func (b *backend) fullArn(ctx context.Context, e *iamEntity, s logical.Storage) } } +// getMetadataValue attempts to get a metadata key from +// auth.InternalData and if unset, auth.Metadata. If not +// found, returns "". +func getMetadataValue(fromAuth *logical.Auth, forKey string) (string, error) { + if raw, ok := fromAuth.InternalData[forKey]; ok { + if val, ok := raw.(string); ok { + return val, nil + } else { + return "", fmt.Errorf("unable to fetch %q from auth metadata due to type of %T", forKey, raw) + } + } + if val, ok := fromAuth.Metadata[forKey]; ok { + return val, nil + } + return "", fmt.Errorf("%q not found in auth metadata", forKey) +} + const iamServerIdHeader = "X-Vault-AWS-IAM-Server-ID" const pathLoginSyn = `