github.com/hashicorp/vault/sdk@v0.11.0/helper/tokenutil/tokenutil.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package tokenutil
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"time"
    10  
    11  	"github.com/hashicorp/go-secure-stdlib/parseutil"
    12  	"github.com/hashicorp/go-secure-stdlib/strutil"
    13  	sockaddr "github.com/hashicorp/go-sockaddr"
    14  	"github.com/hashicorp/vault/sdk/framework"
    15  	"github.com/hashicorp/vault/sdk/helper/policyutil"
    16  	"github.com/hashicorp/vault/sdk/logical"
    17  )
    18  
    19  // TokenParams contains a set of common parameters that auth plugins can use
    20  // for setting token behavior
    21  type TokenParams struct {
    22  	// The set of CIDRs that tokens generated using this role will be bound to
    23  	TokenBoundCIDRs []*sockaddr.SockAddrMarshaler `json:"token_bound_cidrs"`
    24  
    25  	// If set, the token entry will have an explicit maximum TTL set, rather
    26  	// than deferring to role/mount values
    27  	TokenExplicitMaxTTL time.Duration `json:"token_explicit_max_ttl" mapstructure:"token_explicit_max_ttl"`
    28  
    29  	// The max TTL to use for the token
    30  	TokenMaxTTL time.Duration `json:"token_max_ttl" mapstructure:"token_max_ttl"`
    31  
    32  	// If set, core will not automatically add default to the policy list
    33  	TokenNoDefaultPolicy bool `json:"token_no_default_policy" mapstructure:"token_no_default_policy"`
    34  
    35  	// The maximum number of times a token issued from this role may be used.
    36  	TokenNumUses int `json:"token_num_uses" mapstructure:"token_num_uses"`
    37  
    38  	// If non-zero, tokens created using this role will be able to be renewed
    39  	// forever, but will have a fixed renewal period of this value
    40  	TokenPeriod time.Duration `json:"token_period" mapstructure:"token_period"`
    41  
    42  	// The policies to set
    43  	TokenPolicies []string `json:"token_policies" mapstructure:"token_policies"`
    44  
    45  	// The type of token this role should issue
    46  	TokenType logical.TokenType `json:"token_type" mapstructure:"token_type"`
    47  
    48  	// The TTL to user for the token
    49  	TokenTTL time.Duration `json:"token_ttl" mapstructure:"token_ttl"`
    50  }
    51  
    52  // AddTokenFields adds fields to an existing role. It panics if it would
    53  // overwrite an existing field.
    54  func AddTokenFields(m map[string]*framework.FieldSchema) {
    55  	AddTokenFieldsWithAllowList(m, nil)
    56  }
    57  
    58  // AddTokenFields adds fields to an existing role. It panics if it would
    59  // overwrite an existing field. Allowed can be use to restrict the set, e.g. if
    60  // there would be conflicts.
    61  func AddTokenFieldsWithAllowList(m map[string]*framework.FieldSchema, allowed []string) {
    62  	r := TokenFields()
    63  	for k, v := range r {
    64  		if len(allowed) > 0 && !strutil.StrListContains(allowed, k) {
    65  			continue
    66  		}
    67  		if _, has := m[k]; has {
    68  			panic(fmt.Sprintf("adding role field %s would overwrite existing field", k))
    69  		}
    70  		m[k] = v
    71  	}
    72  }
    73  
    74  // TokenFields provides a set of field schemas for the parameters
    75  func TokenFields() map[string]*framework.FieldSchema {
    76  	return map[string]*framework.FieldSchema{
    77  		"token_bound_cidrs": {
    78  			Type:        framework.TypeCommaStringSlice,
    79  			Description: `Comma separated string or JSON list of CIDR blocks. If set, specifies the blocks of IP addresses which are allowed to use the generated token.`,
    80  			DisplayAttrs: &framework.DisplayAttributes{
    81  				Name:        "Generated Token's Bound CIDRs",
    82  				Group:       "Tokens",
    83  				Description: "A list of CIDR blocks. If set, specifies the blocks of IP addresses which are allowed to use the generated token.",
    84  			},
    85  		},
    86  
    87  		"token_explicit_max_ttl": {
    88  			Type:        framework.TypeDurationSecond,
    89  			Description: tokenExplicitMaxTTLHelp,
    90  			DisplayAttrs: &framework.DisplayAttributes{
    91  				Name:  "Generated Token's Explicit Maximum TTL",
    92  				Group: "Tokens",
    93  			},
    94  		},
    95  
    96  		"token_max_ttl": {
    97  			Type:        framework.TypeDurationSecond,
    98  			Description: "The maximum lifetime of the generated token",
    99  			DisplayAttrs: &framework.DisplayAttributes{
   100  				Name:  "Generated Token's Maximum TTL",
   101  				Group: "Tokens",
   102  			},
   103  		},
   104  
   105  		"token_no_default_policy": {
   106  			Type:        framework.TypeBool,
   107  			Description: "If true, the 'default' policy will not automatically be added to generated tokens",
   108  			DisplayAttrs: &framework.DisplayAttributes{
   109  				Name:  "Do Not Attach 'default' Policy To Generated Tokens",
   110  				Group: "Tokens",
   111  			},
   112  		},
   113  
   114  		"token_period": {
   115  			Type:        framework.TypeDurationSecond,
   116  			Description: tokenPeriodHelp,
   117  			DisplayAttrs: &framework.DisplayAttributes{
   118  				Name:  "Generated Token's Period",
   119  				Group: "Tokens",
   120  			},
   121  		},
   122  
   123  		"token_policies": {
   124  			Type:        framework.TypeCommaStringSlice,
   125  			Description: "Comma-separated list of policies",
   126  			DisplayAttrs: &framework.DisplayAttributes{
   127  				Name:        "Generated Token's Policies",
   128  				Group:       "Tokens",
   129  				Description: "A list of policies that will apply to the generated token for this user.",
   130  			},
   131  		},
   132  
   133  		"token_type": {
   134  			Type:        framework.TypeString,
   135  			Default:     "default-service",
   136  			Description: "The type of token to generate, service or batch",
   137  			DisplayAttrs: &framework.DisplayAttributes{
   138  				Name:  "Generated Token's Type",
   139  				Group: "Tokens",
   140  			},
   141  		},
   142  
   143  		"token_ttl": {
   144  			Type:        framework.TypeDurationSecond,
   145  			Description: "The initial ttl of the token to generate",
   146  			DisplayAttrs: &framework.DisplayAttributes{
   147  				Name:  "Generated Token's Initial TTL",
   148  				Group: "Tokens",
   149  			},
   150  		},
   151  
   152  		"token_num_uses": {
   153  			Type:        framework.TypeInt,
   154  			Description: "The maximum number of times a token may be used, a value of zero means unlimited",
   155  			DisplayAttrs: &framework.DisplayAttributes{
   156  				Name:  "Maximum Uses of Generated Tokens",
   157  				Group: "Tokens",
   158  			},
   159  		},
   160  	}
   161  }
   162  
   163  // ParseTokenFields provides common field parsing functionality into a TokenFields struct
   164  func (t *TokenParams) ParseTokenFields(req *logical.Request, d *framework.FieldData) error {
   165  	if boundCIDRsRaw, ok := d.GetOk("token_bound_cidrs"); ok {
   166  		boundCIDRs, err := parseutil.ParseAddrs(boundCIDRsRaw.([]string))
   167  		if err != nil {
   168  			return err
   169  		}
   170  		t.TokenBoundCIDRs = boundCIDRs
   171  	}
   172  
   173  	if explicitMaxTTLRaw, ok := d.GetOk("token_explicit_max_ttl"); ok {
   174  		t.TokenExplicitMaxTTL = time.Duration(explicitMaxTTLRaw.(int)) * time.Second
   175  	}
   176  
   177  	if maxTTLRaw, ok := d.GetOk("token_max_ttl"); ok {
   178  		t.TokenMaxTTL = time.Duration(maxTTLRaw.(int)) * time.Second
   179  	}
   180  	if t.TokenMaxTTL < 0 {
   181  		return errors.New("'token_max_ttl' cannot be negative")
   182  	}
   183  
   184  	if noDefaultRaw, ok := d.GetOk("token_no_default_policy"); ok {
   185  		t.TokenNoDefaultPolicy = noDefaultRaw.(bool)
   186  	}
   187  
   188  	if periodRaw, ok := d.GetOk("token_period"); ok {
   189  		t.TokenPeriod = time.Duration(periodRaw.(int)) * time.Second
   190  	}
   191  	if t.TokenPeriod < 0 {
   192  		return errors.New("'token_period' cannot be negative")
   193  	}
   194  
   195  	if policiesRaw, ok := d.GetOk("token_policies"); ok {
   196  		t.TokenPolicies = policiesRaw.([]string)
   197  	}
   198  
   199  	if tokenTypeRaw, ok := d.GetOk("token_type"); ok {
   200  		var tokenType logical.TokenType
   201  		tokenTypeStr := tokenTypeRaw.(string)
   202  		switch tokenTypeStr {
   203  		case "", "default":
   204  			tokenType = logical.TokenTypeDefault
   205  		case "service":
   206  			tokenType = logical.TokenTypeService
   207  		case "batch":
   208  			tokenType = logical.TokenTypeBatch
   209  		default:
   210  			return fmt.Errorf("invalid 'token_type' value %q", tokenTypeStr)
   211  		}
   212  		t.TokenType = tokenType
   213  	}
   214  
   215  	if tokenNumUses, ok := d.GetOk("token_num_uses"); ok {
   216  		t.TokenNumUses = tokenNumUses.(int)
   217  	}
   218  	if t.TokenNumUses < 0 {
   219  		return errors.New("'token_num_uses' cannot be negative")
   220  	}
   221  
   222  	if t.TokenType == logical.TokenTypeBatch || t.TokenType == logical.TokenTypeDefaultBatch {
   223  		if t.TokenPeriod != 0 {
   224  			return errors.New("'token_type' cannot be 'batch' or 'default_batch' when set to generate periodic tokens")
   225  		}
   226  		if t.TokenNumUses != 0 {
   227  			return errors.New("'token_type' cannot be 'batch' or 'default_batch' when set to generate tokens with limited use count")
   228  		}
   229  	}
   230  
   231  	if ttlRaw, ok := d.GetOk("token_ttl"); ok {
   232  		t.TokenTTL = time.Duration(ttlRaw.(int)) * time.Second
   233  	}
   234  	if t.TokenTTL < 0 {
   235  		return errors.New("'token_ttl' cannot be negative")
   236  	}
   237  	if t.TokenTTL > 0 && t.TokenMaxTTL > 0 && t.TokenTTL > t.TokenMaxTTL {
   238  		return errors.New("'token_ttl' cannot be greater than 'token_max_ttl'")
   239  	}
   240  
   241  	return nil
   242  }
   243  
   244  // PopulateTokenData adds information from TokenParams into the map
   245  func (t *TokenParams) PopulateTokenData(m map[string]interface{}) {
   246  	m["token_bound_cidrs"] = t.TokenBoundCIDRs
   247  	m["token_explicit_max_ttl"] = int64(t.TokenExplicitMaxTTL.Seconds())
   248  	m["token_max_ttl"] = int64(t.TokenMaxTTL.Seconds())
   249  	m["token_no_default_policy"] = t.TokenNoDefaultPolicy
   250  	m["token_period"] = int64(t.TokenPeriod.Seconds())
   251  	m["token_policies"] = t.TokenPolicies
   252  	m["token_type"] = t.TokenType.String()
   253  	m["token_ttl"] = int64(t.TokenTTL.Seconds())
   254  	m["token_num_uses"] = t.TokenNumUses
   255  
   256  	if len(t.TokenPolicies) == 0 {
   257  		m["token_policies"] = []string{}
   258  	}
   259  
   260  	if len(t.TokenBoundCIDRs) == 0 {
   261  		m["token_bound_cidrs"] = []string{}
   262  	}
   263  }
   264  
   265  // PopulateTokenAuth populates Auth with parameters
   266  func (t *TokenParams) PopulateTokenAuth(auth *logical.Auth) {
   267  	auth.BoundCIDRs = t.TokenBoundCIDRs
   268  	auth.ExplicitMaxTTL = t.TokenExplicitMaxTTL
   269  	auth.MaxTTL = t.TokenMaxTTL
   270  	auth.NoDefaultPolicy = t.TokenNoDefaultPolicy
   271  	auth.Period = t.TokenPeriod
   272  	auth.Policies = t.TokenPolicies
   273  	auth.Renewable = true
   274  	auth.TokenType = t.TokenType
   275  	auth.TTL = t.TokenTTL
   276  	auth.NumUses = t.TokenNumUses
   277  }
   278  
   279  func DeprecationText(param string) string {
   280  	return fmt.Sprintf("Use %q instead. If this and %q are both specified, only %q will be used.", param, param, param)
   281  }
   282  
   283  func upgradeDurationValue(d *framework.FieldData, oldKey, newKey string, oldVal, newVal *time.Duration) error {
   284  	_, ok := d.GetOk(newKey)
   285  	if !ok {
   286  		raw, ok := d.GetOk(oldKey)
   287  		if ok {
   288  			*oldVal = time.Duration(raw.(int)) * time.Second
   289  			*newVal = *oldVal
   290  		}
   291  	} else {
   292  		_, ok = d.GetOk(oldKey)
   293  		if ok {
   294  			*oldVal = *newVal
   295  		} else {
   296  			*oldVal = 0
   297  		}
   298  	}
   299  
   300  	return nil
   301  }
   302  
   303  func upgradeIntValue(d *framework.FieldData, oldKey, newKey string, oldVal, newVal *int) error {
   304  	_, ok := d.GetOk(newKey)
   305  	if !ok {
   306  		raw, ok := d.GetOk(oldKey)
   307  		if ok {
   308  			*oldVal = raw.(int)
   309  			*newVal = *oldVal
   310  		}
   311  	} else {
   312  		_, ok = d.GetOk(oldKey)
   313  		if ok {
   314  			*oldVal = *newVal
   315  		} else {
   316  			*oldVal = 0
   317  		}
   318  	}
   319  
   320  	return nil
   321  }
   322  
   323  func upgradeStringSliceValue(d *framework.FieldData, oldKey, newKey string, oldVal, newVal *[]string) error {
   324  	_, ok := d.GetOk(newKey)
   325  	if !ok {
   326  		raw, ok := d.GetOk(oldKey)
   327  		if ok {
   328  			// Special case: if we're looking at "token_policies" parse the policies
   329  			if newKey == "token_policies" {
   330  				*oldVal = policyutil.ParsePolicies(raw)
   331  			} else {
   332  				*oldVal = raw.([]string)
   333  			}
   334  			*newVal = *oldVal
   335  		}
   336  	} else {
   337  		_, ok = d.GetOk(oldKey)
   338  		if ok {
   339  			*oldVal = *newVal
   340  		} else {
   341  			*oldVal = nil
   342  		}
   343  	}
   344  
   345  	return nil
   346  }
   347  
   348  func upgradeSockAddrSliceValue(d *framework.FieldData, oldKey, newKey string, oldVal, newVal *[]*sockaddr.SockAddrMarshaler) error {
   349  	_, ok := d.GetOk(newKey)
   350  	if !ok {
   351  		raw, ok := d.GetOk(oldKey)
   352  		if ok {
   353  			boundCIDRs, err := parseutil.ParseAddrs(raw)
   354  			if err != nil {
   355  				return err
   356  			}
   357  			*oldVal = boundCIDRs
   358  			*newVal = *oldVal
   359  		}
   360  	} else {
   361  		_, ok = d.GetOk(oldKey)
   362  		if ok {
   363  			*oldVal = *newVal
   364  		} else {
   365  			*oldVal = nil
   366  		}
   367  	}
   368  
   369  	return nil
   370  }
   371  
   372  // UpgradeValue takes in old/new data keys and old/new values and calls out to
   373  // a helper function to perform upgrades in a standardized way. It reqiures
   374  // pointers in all cases so that we can set directly into the target struct.
   375  func UpgradeValue(d *framework.FieldData, oldKey, newKey string, oldVal, newVal interface{}) error {
   376  	switch typedOldVal := oldVal.(type) {
   377  	case *time.Duration:
   378  		typedNewVal, ok := newVal.(*time.Duration)
   379  		if !ok {
   380  			return errors.New("mismatch in value types in tokenutil.UpgradeValue")
   381  		}
   382  		return upgradeDurationValue(d, oldKey, newKey, typedOldVal, typedNewVal)
   383  
   384  	case *int:
   385  		typedNewVal, ok := newVal.(*int)
   386  		if !ok {
   387  			return errors.New("mismatch in value types in tokenutil.UpgradeValue")
   388  		}
   389  		return upgradeIntValue(d, oldKey, newKey, typedOldVal, typedNewVal)
   390  
   391  	case *[]string:
   392  		typedNewVal, ok := newVal.(*[]string)
   393  		if !ok {
   394  			return errors.New("mismatch in value types in tokenutil.UpgradeValue")
   395  		}
   396  		return upgradeStringSliceValue(d, oldKey, newKey, typedOldVal, typedNewVal)
   397  
   398  	case *[]*sockaddr.SockAddrMarshaler:
   399  		typedNewVal, ok := newVal.(*[]*sockaddr.SockAddrMarshaler)
   400  		if !ok {
   401  			return errors.New("mismatch in value types in tokenutil.UpgradeValue")
   402  		}
   403  		return upgradeSockAddrSliceValue(d, oldKey, newKey, typedOldVal, typedNewVal)
   404  
   405  	default:
   406  		return errors.New("unhandled type in tokenutil.UpgradeValue")
   407  	}
   408  }
   409  
   410  const (
   411  	tokenPeriodHelp = `If set, tokens created via this role
   412  will have no max lifetime; instead, their
   413  renewal period will be fixed to this value.
   414  This takes an integer number of seconds,
   415  or a string duration (e.g. "24h").`
   416  	tokenExplicitMaxTTLHelp = `If set, tokens created via this role
   417  carry an explicit maximum TTL. During renewal,
   418  the current maximum TTL values of the role
   419  and the mount are not checked for changes,
   420  and any updates to these values will have
   421  no effect on the token being renewed.`
   422  )