...
1
16
17 package util
18
19 import (
20 "crypto/rand"
21 "fmt"
22 "math/big"
23 "regexp"
24 "strings"
25
26 "k8s.io/apimachinery/pkg/util/sets"
27 "k8s.io/cluster-bootstrap/token/api"
28 )
29
30
31
32
33 const validBootstrapTokenChars = "0123456789abcdefghijklmnopqrstuvwxyz"
34
35 var (
36
37 BootstrapTokenRegexp = regexp.MustCompile(api.BootstrapTokenPattern)
38
39 BootstrapTokenIDRegexp = regexp.MustCompile(api.BootstrapTokenIDPattern)
40
41 BootstrapGroupRegexp = regexp.MustCompile(api.BootstrapGroupPattern)
42 )
43
44
45 func GenerateBootstrapToken() (string, error) {
46 tokenID, err := randBytes(api.BootstrapTokenIDBytes)
47 if err != nil {
48 return "", err
49 }
50
51 tokenSecret, err := randBytes(api.BootstrapTokenSecretBytes)
52 if err != nil {
53 return "", err
54 }
55
56 return TokenFromIDAndSecret(tokenID, tokenSecret), nil
57 }
58
59
60
61 func randBytes(length int) (string, error) {
62 var (
63 token = make([]byte, length)
64 max = new(big.Int).SetUint64(uint64(len(validBootstrapTokenChars)))
65 )
66
67 for i := range token {
68 val, err := rand.Int(rand.Reader, max)
69 if err != nil {
70 return "", fmt.Errorf("could not generate random integer: %w", err)
71 }
72
73
74 x := val.Uint64()
75 res := x + 48 + (39 & ((9 - x) >> 8))
76 token[i] = byte(res)
77 }
78
79 return string(token), nil
80 }
81
82
83 func TokenFromIDAndSecret(id, secret string) string {
84 return fmt.Sprintf("%s.%s", id, secret)
85 }
86
87
88
89
90 func IsValidBootstrapToken(token string) bool {
91
92 t := strings.Split(token, ".")
93 if len(t) != 2 {
94 return false
95 }
96
97
98
99 if !BootstrapTokenIDRegexp.MatchString(t[0]) {
100 return false
101 }
102
103
104 secret := t[1]
105 if len(secret) != api.BootstrapTokenSecretBytes {
106 return false
107 }
108 for i := range secret {
109 c := int(secret[i])
110 notDigit := (c < 48 || c > 57)
111 notLetter := (c < 97 || c > 122)
112 if notDigit && notLetter {
113 return false
114 }
115 }
116 return true
117 }
118
119
120
121 func IsValidBootstrapTokenID(tokenID string) bool {
122 return BootstrapTokenIDRegexp.MatchString(tokenID)
123 }
124
125
126
127 func BootstrapTokenSecretName(tokenID string) string {
128 return fmt.Sprintf("%s%s", api.BootstrapTokenSecretPrefix, tokenID)
129 }
130
131
132
133
134 func ValidateBootstrapGroupName(name string) error {
135 if BootstrapGroupRegexp.Match([]byte(name)) {
136 return nil
137 }
138 return fmt.Errorf("bootstrap group %q is invalid (must match %s)", name, api.BootstrapGroupPattern)
139 }
140
141
142 func ValidateUsages(usages []string) error {
143 validUsages := sets.NewString(api.KnownTokenUsages...)
144 invalidUsages := sets.NewString()
145 for _, usage := range usages {
146 if !validUsages.Has(usage) {
147 invalidUsages.Insert(usage)
148 }
149 }
150 if len(invalidUsages) > 0 {
151 return fmt.Errorf("invalid bootstrap token usage string: %s, valid usage options: %s", strings.Join(invalidUsages.List(), ","), strings.Join(api.KnownTokenUsages, ","))
152 }
153 return nil
154 }
155
View as plain text