github.com/hashicorp/vault/sdk@v0.13.0/framework/lease.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package framework 5 6 import ( 7 "context" 8 "fmt" 9 "strings" 10 "time" 11 12 "github.com/hashicorp/vault/sdk/logical" 13 ) 14 15 // LeaseExtend is left for backwards compatibility for plugins. This function 16 // now just passes back the data that was passed into it to be processed in core. 17 // DEPRECATED 18 func LeaseExtend(backendIncrement, backendMax time.Duration, systemView logical.SystemView) OperationFunc { 19 return func(ctx context.Context, req *logical.Request, data *FieldData) (*logical.Response, error) { 20 switch { 21 case req.Auth != nil: 22 req.Auth.TTL = backendIncrement 23 req.Auth.MaxTTL = backendMax 24 return &logical.Response{Auth: req.Auth}, nil 25 case req.Secret != nil: 26 req.Secret.TTL = backendIncrement 27 req.Secret.MaxTTL = backendMax 28 return &logical.Response{Secret: req.Secret}, nil 29 } 30 return nil, fmt.Errorf("no lease options for request") 31 } 32 } 33 34 // CalculateTTL takes all the user-specified, backend, and system inputs and calculates 35 // a TTL for a lease 36 func CalculateTTL(sysView logical.SystemView, increment, backendTTL, period, backendMaxTTL, explicitMaxTTL time.Duration, startTime time.Time) (ttl time.Duration, warnings []string, errors error) { 37 // Truncate all times to the second since that is the lowest precision for 38 // TTLs 39 now := time.Now().Truncate(time.Second) 40 if startTime.IsZero() { 41 startTime = now 42 } else { 43 startTime = startTime.Truncate(time.Second) 44 } 45 46 // Use the mount's configured max unless the backend specifies 47 // something more restrictive (perhaps from a role configuration 48 // parameter) 49 maxTTL := sysView.MaxLeaseTTL() 50 if backendMaxTTL > 0 && backendMaxTTL < maxTTL { 51 maxTTL = backendMaxTTL 52 } 53 if explicitMaxTTL > 0 && explicitMaxTTL < maxTTL { 54 maxTTL = explicitMaxTTL 55 } 56 57 // Should never happen, but guard anyways 58 if maxTTL <= 0 { 59 return 0, nil, fmt.Errorf("max TTL must be greater than zero") 60 } 61 62 var maxValidTime time.Time 63 switch { 64 case period > 0: 65 // Cap the period value to the sys max_ttl value 66 if period > maxTTL { 67 warnings = append(warnings, 68 fmt.Sprintf("period of %q exceeded the effective max_ttl of %q; period value is capped accordingly", 69 humanDuration(period), humanDuration(maxTTL))) 70 period = maxTTL 71 } 72 ttl = period 73 74 if explicitMaxTTL > 0 { 75 maxValidTime = startTime.Add(explicitMaxTTL) 76 } 77 default: 78 switch { 79 case increment > 0: 80 ttl = increment 81 case backendTTL > 0: 82 ttl = backendTTL 83 default: 84 ttl = sysView.DefaultLeaseTTL() 85 } 86 87 // We cannot go past this time 88 maxValidTime = startTime.Add(maxTTL) 89 } 90 91 if !maxValidTime.IsZero() { 92 // Determine the max valid TTL 93 maxValidTTL := maxValidTime.Sub(now) 94 95 // If we are past the max TTL, we shouldn't be in this function...but 96 // fast path out if we are 97 if maxValidTTL <= 0 { 98 return 0, nil, fmt.Errorf("past the max TTL, cannot renew") 99 } 100 101 // If the proposed expiration is after the maximum TTL of the lease, 102 // cap the increment to whatever is left 103 if maxValidTTL-ttl < 0 { 104 warnings = append(warnings, 105 fmt.Sprintf("TTL of %q exceeded the effective max_ttl of %q; TTL value is capped accordingly", 106 humanDuration(ttl), humanDuration(maxValidTTL))) 107 ttl = maxValidTTL 108 } 109 } 110 111 return ttl, warnings, nil 112 } 113 114 // humanDuration prints the time duration without zero elements. 115 func humanDuration(d time.Duration) string { 116 if d == 0 { 117 return "0s" 118 } 119 120 s := d.String() 121 if strings.HasSuffix(s, "m0s") { 122 s = s[:len(s)-2] 123 } 124 if idx := strings.Index(s, "h0m"); idx > 0 { 125 s = s[:idx+1] + s[idx+3:] 126 } 127 return s 128 }