Skip to content

Commit

Permalink
refactor to also populate auth metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
tyrannosaurus-becks committed Apr 24, 2020
1 parent 3cbce69 commit ae3ba7f
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 200 deletions.
38 changes: 19 additions & 19 deletions builtin/credential/aws/path_config_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import (
"fmt"

"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/aliasmetadata"
"github.com/hashicorp/vault/sdk/helper/authmetadata"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/logical"
)

var (
// iamAliasMetadataFields is a list of the default alias metadata
// iamAuthMetadataFields is a list of the default auth metadata
// added to tokens during login. The default alias type used
// by this back-end is the role ID. Subsequently, the default
// fields included are expected to have a low rate of change
// when the role ID is in use.
iamAliasMetadataFields = &aliasmetadata.Fields{
iamAuthMetadataFields = &authmetadata.Fields{
FieldName: "iam_metadata",
Default: []string{
"account_id",
Expand All @@ -32,12 +32,12 @@ var (
},
}

// ec2AliasMetadataFields is a list of the default alias metadata
// ec2AuthMetadataFields is a list of the default auth metadata
// added to tokens during login. The default alias type used
// by this back-end is the role ID. Subsequently, the default
// fields included are expected to have a low rate of change
// when the role ID is in use.
ec2AliasMetadataFields = &aliasmetadata.Fields{
ec2AuthMetadataFields = &authmetadata.Fields{
FieldName: "ec2_metadata",
Default: []string{
"account_id",
Expand All @@ -59,13 +59,13 @@ func (b *backend) pathConfigIdentity() *framework.Path {
Default: identityAliasIAMUniqueID,
Description: fmt.Sprintf("Configure how the AWS auth method generates entity aliases when using IAM auth. Valid values are %q, %q, and %q. Defaults to %q.", identityAliasRoleID, identityAliasIAMUniqueID, identityAliasIAMFullArn, identityAliasRoleID),
},
iamAliasMetadataFields.FieldName: aliasmetadata.FieldSchema(iamAliasMetadataFields),
iamAuthMetadataFields.FieldName: authmetadata.FieldSchema(iamAuthMetadataFields),
"ec2_alias": {
Type: framework.TypeString,
Default: identityAliasEC2InstanceID,
Description: fmt.Sprintf("Configure how the AWS auth method generates entity alias when using EC2 auth. Valid values are %q, %q, and %q. Defaults to %q.", identityAliasRoleID, identityAliasEC2InstanceID, identityAliasEC2ImageID, identityAliasRoleID),
},
ec2AliasMetadataFields.FieldName: aliasmetadata.FieldSchema(ec2AliasMetadataFields),
ec2AuthMetadataFields.FieldName: authmetadata.FieldSchema(ec2AuthMetadataFields),
},

Operations: map[logical.Operation]framework.OperationHandler{
Expand All @@ -89,8 +89,8 @@ func identityConfigEntry(ctx context.Context, s logical.Storage) (*identityConfi
}

entry := &identityConfig{
IAMAliasMetadataHandler: aliasmetadata.NewHandler(iamAliasMetadataFields),
EC2AliasMetadataHandler: aliasmetadata.NewHandler(ec2AliasMetadataFields),
IAMAuthMetadataHandler: authmetadata.NewHandler(iamAuthMetadataFields),
EC2AuthMetadataHandler: authmetadata.NewHandler(ec2AuthMetadataFields),
}
if entryRaw != nil {
if err := entryRaw.DecodeJSON(entry); err != nil {
Expand All @@ -117,10 +117,10 @@ func pathConfigIdentityRead(ctx context.Context, req *logical.Request, _ *framew

return &logical.Response{
Data: map[string]interface{}{
"iam_alias": config.IAMAlias,
iamAliasMetadataFields.FieldName: config.IAMAliasMetadataHandler.AliasMetadata(),
"ec2_alias": config.EC2Alias,
ec2AliasMetadataFields.FieldName: config.EC2AliasMetadataHandler.AliasMetadata(),
"iam_alias": config.IAMAlias,
iamAuthMetadataFields.FieldName: config.IAMAuthMetadataHandler.AuthMetadata(),
"ec2_alias": config.EC2Alias,
ec2AuthMetadataFields.FieldName: config.EC2AuthMetadataHandler.AuthMetadata(),
},
}, nil
}
Expand Down Expand Up @@ -150,10 +150,10 @@ func pathConfigIdentityUpdate(ctx context.Context, req *logical.Request, data *f
}
config.EC2Alias = ec2Alias
}
if err := config.IAMAliasMetadataHandler.ParseAliasMetadata(data); err != nil {
if err := config.IAMAuthMetadataHandler.ParseAuthMetadata(data); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
if err := config.EC2AliasMetadataHandler.ParseAliasMetadata(data); err != nil {
if err := config.EC2AuthMetadataHandler.ParseAuthMetadata(data); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}

Expand All @@ -171,10 +171,10 @@ func pathConfigIdentityUpdate(ctx context.Context, req *logical.Request, data *f
}

type identityConfig struct {
IAMAlias string `json:"iam_alias"`
IAMAliasMetadataHandler *aliasmetadata.Handler `json:"iam_alias_metadata_handler"`
EC2Alias string `json:"ec2_alias"`
EC2AliasMetadataHandler *aliasmetadata.Handler `json:"ec2_alias_metadata_handler"`
IAMAlias string `json:"iam_alias"`
IAMAuthMetadataHandler *authmetadata.Handler `json:"iam_auth_metadata_handler"`
EC2Alias string `json:"ec2_alias"`
EC2AuthMetadataHandler *authmetadata.Handler `json:"ec2_auth_metadata_handler"`
}

const identityAliasIAMUniqueID = "unique_id"
Expand Down
18 changes: 3 additions & 15 deletions builtin/credential/aws/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,19 +836,15 @@ func (b *backend) pathLoginUpdateEc2(ctx context.Context, req *logical.Request,

auth := &logical.Auth{
Metadata: map[string]string{
"instance_id": identityDocParsed.InstanceID,
"region": identityDocParsed.Region,
"account_id": identityDocParsed.AccountID,
"role_tag_max_ttl": rTagMaxTTL.String(),
"role": roleName,
"ami_id": identityDocParsed.AmiID,
},
Alias: &logical.Alias{
Name: identityAlias,
},
}
roleEntry.PopulateTokenAuth(auth)
if err := identityConfigEntry.EC2AliasMetadataHandler.PopulateDesiredAliasMetadata(auth, map[string]string{
if err := identityConfigEntry.EC2AuthMetadataHandler.PopulateDesiredMetadata(auth, map[string]string{
"instance_id": identityDocParsed.InstanceID,
"region": identityDocParsed.Region,
"account_id": identityDocParsed.AccountID,
Expand Down Expand Up @@ -1360,15 +1356,7 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request,

auth := &logical.Auth{
Metadata: map[string]string{
"client_arn": callerID.Arn,
"canonical_arn": entity.canonicalArn(),
"client_user_id": callerUniqueId,
"auth_type": iamAuthType,
"inferred_entity_type": inferredEntityType,
"inferred_entity_id": inferredEntityID,
"inferred_aws_region": roleEntry.InferredAWSRegion,
"account_id": entity.AccountNumber,
"role_id": roleEntry.RoleID,
"role_id": roleEntry.RoleID,
},
InternalData: map[string]interface{}{
"role_name": roleName,
Expand All @@ -1380,7 +1368,7 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request,
},
}
roleEntry.PopulateTokenAuth(auth)
if err := identityConfigEntry.IAMAliasMetadataHandler.PopulateDesiredAliasMetadata(auth, map[string]string{
if err := identityConfigEntry.IAMAuthMetadataHandler.PopulateDesiredMetadata(auth, map[string]string{
"client_arn": callerID.Arn,
"canonical_arn": entity.canonicalArn(),
"client_user_id": callerUniqueId,
Expand Down
6 changes: 3 additions & 3 deletions builtin/credential/aws/path_login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func TestBackend_pathLogin_IAMHeaders(t *testing.T) {
t.Fatal(err)
}

expectedAliasMetadata := map[string]string{
expectedAuthMetadata := map[string]string{
"account_id": "123456789012",
"auth_type": "iam",
"canonical_arn": "arn:aws:iam::123456789012:user/valid-role",
Expand Down Expand Up @@ -370,8 +370,8 @@ func TestBackend_pathLogin_IAMHeaders(t *testing.T) {
t.Errorf("un expected failed login:\nresp: %#v\n\nerr: %v", resp, err)
}

if !reflect.DeepEqual(expectedAliasMetadata, resp.Auth.Alias.Metadata) {
t.Errorf("expected metadata (%#v) to match (%#v)", expectedAliasMetadata, resp.Auth.Alias.Metadata)
if !reflect.DeepEqual(expectedAuthMetadata, resp.Auth.Alias.Metadata) {
t.Errorf("expected metadata (%#v) to match (%#v)", expectedAuthMetadata, resp.Auth.Alias.Metadata)
}
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package aliasmetadata
package authmetadata

/*
aliasmetadata is a package offering convenience and
standardization when supporting an `alias_metadata`
authmetadata is a package offering convenience and
standardization when supporting an `auth_metadata`
field in a plugin's configuration. This then controls
what alias metadata is added to an Auth during login.
what metadata is added to an Auth during login.
To see an example of how to add and use it, check out
how these structs and fields are used in the AWS auth
Expand Down Expand Up @@ -52,14 +52,14 @@ func (f *Fields) all() []string {

// FieldSchema takes the default and additionally available
// fields, and uses them to generate a verbose description
// regarding how to use the "alias_metadata" field.
// regarding how to use the "auth_metadata" field.
func FieldSchema(fields *Fields) *framework.FieldSchema {
return &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: description(fields),
DisplayAttrs: &framework.DisplayAttributes{
Name: fields.FieldName,
Value: "default,field1,field2",
Value: "field1,field2",
},
Default: []string{"default"},
}
Expand All @@ -72,35 +72,32 @@ func NewHandler(fields *Fields) *Handler {
}

type Handler struct {
// aliasMetadata is an explicit list of all the user's configured
// fields that are being added to alias metadata. It will never
// include the "default" parameter, and instead includes the actual
// fields behind "default", if selected. If it has never been set
// or only the default fields are desired, it is nil.
aliasMetadata []string
// authMetadata is an explicit list of all the user's configured
// fields that are being added to auth metadata. If it is set to
// default or unconfigured, it will be nil. Otherwise, it will
// hold the explicit fields set by the user.
authMetadata []string

// fields is a list of the configured default and available
// fields. It's intentionally not jsonified.
// fields.
fields *Fields
}

// AliasMetadata is intended to be used on config reads.
// AuthMetadata is intended to be used on config reads.
// It gets an explicit list of all the user's configured
// fields that are being added to alias metadata. It will never
// include the "default" parameter, and instead includes the actual
// fields behind "default", if selected.
func (h *Handler) AliasMetadata() []string {
if h.aliasMetadata == nil {
// fields that are being added to auth metadata.
func (h *Handler) AuthMetadata() []string {
if h.authMetadata == nil {
return h.fields.Default
}
return h.aliasMetadata
return h.authMetadata
}

// ParseAliasMetadata is intended to be used on config create/update.
// ParseAuthMetadata is intended to be used on config create/update.
// It takes a user's selected fields (or lack thereof),
// converts it to a list of explicit fields, and adds it to the Handler
// for later storage.
func (h *Handler) ParseAliasMetadata(data *framework.FieldData) error {
func (h *Handler) ParseAuthMetadata(data *framework.FieldData) error {
userProvidedRaw, ok := data.GetOk(h.fields.FieldName)
if !ok {
// Nothing further to do here.
Expand All @@ -116,7 +113,7 @@ func (h *Handler) ParseAliasMetadata(data *framework.FieldData) error {
// we don't store anything so we won't have to do a storage
// migration if the default changes.
if len(userProvided) == 1 && userProvided[0] == "default" {
h.aliasMetadata = nil
h.authMetadata = nil
return nil
}

Expand All @@ -129,50 +126,34 @@ func (h *Handler) ParseAliasMetadata(data *framework.FieldData) error {
return fmt.Errorf("%q contains an unavailable field, please select from %q",
strings.Join(userProvided, ", "), strings.Join(h.fields.all(), ", "))
}
h.aliasMetadata = userProvided
h.authMetadata = userProvided
return nil
}

// expandDefaultField looks for the field "default" and, if exists,
// replaces it with the actual default fields signified.
func (h *Handler) expandDefaultField(userProvided []string) (expanded []string) {
for _, field := range userProvided {
if field != "default" {
expanded = append(expanded, field)
continue
}
for _, dfltField := range h.fields.Default {
expanded = append(expanded, dfltField)
}
}
return expanded
}

// PopulateDesiredAliasMetadata is intended to be used during login
// PopulateDesiredMetadata is intended to be used during login
// just before returning an auth.
// It takes the available alias metadata and,
// if the auth should have it, adds it to the auth's alias metadata.
func (h *Handler) PopulateDesiredAliasMetadata(auth *logical.Auth, available map[string]string) error {
// It takes the available auth metadata and,
// if the auth should have it, adds it to the auth's metadata.
func (h *Handler) PopulateDesiredMetadata(auth *logical.Auth, available map[string]string) error {
if auth == nil {
return errors.New("auth is nil")
}
if auth.Alias == nil {
return errors.New("auth alias is nil")
if auth.Metadata == nil {
auth.Metadata = make(map[string]string)
}
if auth.Alias.Name == "" {
// We need the caller to set the alias name or there will
// be nothing for these fields to operate upon.
return errors.New("auth alias name must be set")
if auth.Alias == nil {
auth.Alias = &logical.Alias{}
}
if auth.Alias.Metadata == nil {
auth.Alias.Metadata = make(map[string]string)
}
fieldsToInclude := h.fields.Default
if h.aliasMetadata != nil {
fieldsToInclude = h.aliasMetadata
if h.authMetadata != nil {
fieldsToInclude = h.authMetadata
}
for availableField, itsValue := range available {
if strutil.StrListContains(fieldsToInclude, availableField) {
auth.Metadata[availableField] = itsValue
auth.Alias.Metadata[availableField] = itsValue
}
}
Expand All @@ -181,36 +162,35 @@ func (h *Handler) PopulateDesiredAliasMetadata(auth *logical.Auth, available map

func (h *Handler) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
AliasMetadata []string `json:"alias_metadata"`
AuthMetadata []string `json:"auth_metadata"`
}{
AliasMetadata: h.aliasMetadata,
AuthMetadata: h.authMetadata,
})
}

func (h *Handler) UnmarshalJSON(data []byte) error {
jsonable := &struct {
AliasMetadata []string `json:"alias_metadata"`
AuthMetadata []string `json:"auth_metadata"`
}{
AliasMetadata: h.aliasMetadata,
AuthMetadata: h.authMetadata,
}
if err := json.Unmarshal(data, jsonable); err != nil {
return err
}
h.aliasMetadata = jsonable.AliasMetadata
h.authMetadata = jsonable.AuthMetadata
return nil
}

func description(fields *Fields) string {
desc := "The metadata to include on the aliases generated by this plugin."
desc := "The metadata to include on the aliases and audit logs generated by this plugin."
if len(fields.Default) > 0 {
desc += fmt.Sprintf(" When set to 'default', includes: %s.", strings.Join(fields.Default, ", "))
}
if len(fields.AvailableToAdd) > 0 {
desc += fmt.Sprintf(" These fields are available to add: %s.", strings.Join(fields.AvailableToAdd, ", "))
}
desc += " Not editing this field means the 'default' fields are included." +
" Explicitly setting this field to empty overrides the 'default' and means no alias metadata will be included." +
" Add fields by sending, 'default,field1,field2'." +
" We advise only including fields that change rarely because each change triggers a storage write."
" Explicitly setting this field to empty overrides the 'default' and means no metadata will be included." +
" If not using 'default', explicit fields must be sent like: 'field1,field2'."
return desc
}

0 comments on commit ae3ba7f

Please sign in to comment.