Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AWS auth renewals #8991

Merged
merged 6 commits into from
May 18, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 55 additions & 31 deletions builtin/credential/aws/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,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 @@ -963,9 +968,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 @@ -996,16 +1001,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")
tyrannosaurus-becks marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -1027,9 +1035,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 @@ -1070,28 +1078,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 @@ -1360,8 +1362,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 @@ -1709,6 +1716,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