Skip to content

Commit

Permalink
Token identity support (#6267)
Browse files Browse the repository at this point in the history
* Implemented token backend support for identity

* Fixed tests

* Refactored a few checks for the token entity overwrite. Fixed tests.

* Moved entity alias check up so that the entity and entity alias is only created when it has been specified in allowed_entity_aliases list

* go mod vendor

* Added glob pattern

* Optimized allowed entity alias check

* Added test for asterisk only

* Changed to glob pattern anywhere

* Changed response code in case of failure. Changed globbing pattern check. Added docs.

* Added missing token role get parameter. Added more samples

* Fixed failing tests

* Corrected some cosmetical review points

* Changed response code for invalid provided entity alias

* Fixed minor things

* Fixed failing test
  • Loading branch information
michelvocks authored Jul 1, 2019
1 parent 3485e12 commit e7ed739
Show file tree
Hide file tree
Showing 5 changed files with 456 additions and 23 deletions.
1 change: 1 addition & 0 deletions api/auth_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,5 @@ type TokenCreateRequest struct {
NumUses int `json:"num_uses"`
Renewable *bool `json:"renewable,omitempty"`
Type string `json:"type"`
EntityAlias string `json:"entity_alias"`
}
12 changes: 12 additions & 0 deletions command/token_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type TokenCreateCommand struct {
flagType string
flagMetadata map[string]string
flagPolicies []string
flagEntityAlias string
}

func (c *TokenCreateCommand) Synopsis() string {
Expand Down Expand Up @@ -176,6 +177,16 @@ func (c *TokenCreateCommand) Flags() *FlagSets {
"specified multiple times to attach multiple policies.",
})

f.StringVar(&StringVar{
Name: "entity-alias",
Target: &c.flagEntityAlias,
Default: "",
Usage: "Name of the entity alias to associate with during token creation. " +
"Only works in combination with -role argument and used entity alias " +
"must be listed in allowed_entity_aliases. If this has been specified, " +
"the entity will not be inherited from the parent.",
})

return set
}

Expand Down Expand Up @@ -224,6 +235,7 @@ func (c *TokenCreateCommand) Run(args []string) int {
ExplicitMaxTTL: c.flagExplicitMaxTTL.String(),
Period: c.flagPeriod.String(),
Type: c.flagType,
EntityAlias: c.flagEntityAlias,
}

var secret *api.Secret
Expand Down
93 changes: 78 additions & 15 deletions vault/token_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,18 @@ import (
"errors"
"fmt"
"net/http"
"sync"
"sync/atomic"

"regexp"
"strings"
"sync"
"sync/atomic"
"time"

proto "github.com/golang/protobuf/proto"
"github.com/armon/go-metrics"
"github.com/golang/protobuf/proto"
"github.com/hashicorp/errwrap"
log "github.com/hashicorp/go-hclog"
sockaddr "github.com/hashicorp/go-sockaddr"

metrics "github.com/armon/go-metrics"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/vault/helper/identity"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/framework"
Expand Down Expand Up @@ -397,6 +395,11 @@ func (ts *TokenStore) paths() []*framework.Path {
Description: "Use 'token_bound_cidrs' instead.",
Deprecated: true,
},

"allowed_entity_aliases": &framework.FieldSchema{
Type: framework.TypeCommaStringSlice,
Description: "String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation. This field supports globbing.",
},
},

Callbacks: map[logical.Operation]framework.OperationFunc{
Expand Down Expand Up @@ -611,6 +614,9 @@ type tsRoleEntry struct {

// The set of CIDRs that tokens generated using this role will be bound to
BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"`

// The set of allowed entity aliases used during token creation
AllowedEntityAliases []string `json:"allowed_entity_aliases" mapstructure:"allowed_entity_aliases" structs:"allowed_entity_aliases"`
}

type accessorEntry struct {
Expand Down Expand Up @@ -1819,11 +1825,11 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data
}

var countAccessorList,
countCubbyholeKeys,
deletedCountAccessorEmptyToken,
deletedCountAccessorInvalidToken,
deletedCountInvalidTokenInAccessor,
deletedCountInvalidCubbyholeKey int64
countCubbyholeKeys,
deletedCountAccessorEmptyToken,
deletedCountAccessorInvalidToken,
deletedCountInvalidTokenInAccessor,
deletedCountInvalidCubbyholeKey int64

validCubbyholeKeys := make(map[string]bool)

Expand Down Expand Up @@ -2106,6 +2112,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
NumUses int `mapstructure:"num_uses"`
Period string
Type string `mapstructure:"type"`
EntityAlias string `mapstructure:"entity_alias"`
}
if err := mapstructure.WeakDecode(req.Data, &data); err != nil {
return logical.ErrorResponse(fmt.Sprintf(
Expand Down Expand Up @@ -2202,6 +2209,51 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
logical.ErrInvalidRequest
}

// Verify the entity alias
var explicitEntityID string
if data.EntityAlias != "" {
// Parameter is only allowed in combination with token role
if role == nil {
return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest
}

// Check if there is a concrete match
if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) &&
!strutil.StrListContainsGlob(role.AllowedEntityAliases, data.EntityAlias) {
return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest
}

// Get mount accessor which is required to lookup entity alias
mountValidationResp := ts.core.router.MatchingMountByAccessor(req.MountAccessor)
if mountValidationResp == nil {
return logical.ErrorResponse("auth token mount accessor not found"), nil
}

// Create alias for later processing
alias := &logical.Alias{
Name: data.EntityAlias,
MountAccessor: mountValidationResp.Accessor,
MountType: mountValidationResp.Type,
}

// Create or fetch entity from entity alias
entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias)
if err != nil {
return nil, err
}
if entity == nil {
return nil, errors.New("failed to create or fetch entity from given entity alias")
}

// Validate that the entity is not disabled
if entity.Disabled {
return logical.ErrorResponse("entity from given entity alias is disabled"), logical.ErrPermissionDenied
}

// Set new entity id
explicitEntityID = entity.ID
}

// Setup the token entry
te := logical.TokenEntry{
Parent: req.ClientToken,
Expand Down Expand Up @@ -2434,9 +2486,14 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
}

// At this point, it is clear whether the token is going to be an orphan or
// not. If the token is not going to be an orphan, inherit the parent's
// not. If setEntityID is set, the entity identifier will be overwritten.
// Otherwise, if the token is not going to be an orphan, inherit the parent's
// entity identifier into the child token.
if te.Parent != "" {
switch {
case explicitEntityID != "":
// Overwrite the entity identifier
te.EntityID = explicitEntityID
case te.Parent != "":
te.EntityID = parent.EntityID

// If the parent has bound CIDRs, copy those into the child. We don't
Expand Down Expand Up @@ -2978,6 +3035,7 @@ func (ts *TokenStore) tokenStoreRoleRead(ctx context.Context, req *logical.Reque
"path_suffix": role.PathSuffix,
"renewable": role.Renewable,
"token_type": role.TokenType.String(),
"allowed_entity_aliases": role.AllowedEntityAliases,
},
}

Expand Down Expand Up @@ -3183,6 +3241,11 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logic
}
}

allowedEntityAliasesRaw, ok := data.GetOk("allowed_entity_aliases")
if ok {
entry.AllowedEntityAliases = strutil.RemoveDuplicates(allowedEntityAliasesRaw.([]string), true)
}

ns, err := namespace.FromContext(ctx)
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit e7ed739

Please sign in to comment.