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 )