Skip to content

Commit

Permalink
Fix AWS auth renewals (#8991)
Browse files Browse the repository at this point in the history
* fix aws auth renewals

* Update builtin/credential/aws/path_login.go

Co-authored-by: Jim Kalafut <jkalafut@hashicorp.com>

* debug log missing account_ids

* strip tests and related changes

Co-authored-by: Jim Kalafut <jkalafut@hashicorp.com>
  • Loading branch information
tyrannosaurus-becks and Jim Kalafut committed May 18, 2020
1 parent 2212e25 commit a1d4bcf
Showing 1 changed file with 55 additions and 31 deletions.
86 changes: 55 additions & 31 deletions builtin/credential/aws/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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 := ""
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -1680,6 +1687,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 = `
Expand Down

0 comments on commit a1d4bcf

Please sign in to comment.