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

Token identity support #6267

Merged
merged 16 commits into from
Jul 1, 2019
Merged
Show file tree
Hide file tree
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
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
michelvocks marked this conversation as resolved.
Show resolved Hide resolved
}

// 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