Change:
This issue was reported in the Impact Attackers may determine Bootstrap Token values based on timing-based side channels. This may in turn allow them to establish further attacks against a Kubernetes cluster, including joining nodes to an existing cluster. Feasibility of this attack is contingent on a number of factors including but not limited to the underlying hardware platform running the Kubernetes system, and the deployment landscape. Description Kubernetes Bootstrap Tokens are bearer token credentials employed to authenticate requests against the API server, when creating new clusters or joining new nodes to an existing cluster. NCC Group identified a number of functions that handle the Bootstrap Token, and whose implementations are not constant-time. The function , in package , generates Bootstrap Token secret values; it does so by sampling alphanumeric characters from a table, based on a random secret index. The access time of a table element, and resulting cache memory contents, may vary with the access index, which may assist attackers with inferring partial or full information about a token value. Recommendation When generating a secret token value, ensure that the selection process from the alphanumeric table is done in constant-time. The problem is akin to base64 encoding and decoding in constant-time, as implemented by the BearSSL TLS library. Given a byte in the 0..35 range, which we want to map to a digit range (ASCII values 48 to 57) and lower case character range (ASCII values 97 to 122), the constant-time selection process can be achieved as follows: . In order to increase the level of assurance that the modulo operation is performed in constant-time on various platforms, and despite changes to compilers, consider modeling the modulo operation as an explicit multiply and shift operation. The 1991 Granlund- Montgomery paper explains this technique. Avoid performing regular expression operations on secret data. Consider performing constant-time comparison of values instead. Component kube-apiserver Location Function in file Function in file Anything else we need to know? See umbrella issue for current status of all issues created from these findings. The vendor gave this issue an ID of NCC-E003660-TTV and it was finding 15 of the report under the kube-apiserver section. The vendor considers this issue Informational Risk, High Impact, Undetermined Exploitability To view the original finding, begin on page 42 of the Test Environment Kubernetes 1.24.3
/sig security
/sig cluster-lifecycle
/assign
PR that attempts to fix this:
/triage accepted poked #sig-security at slack for review ^

Discussion:
package util import ( <del> "bufio" </del> "crypto/rand" "fmt" <ins> "math/big" </ins> "regexp" "strings"

// randBytes returns a random string consisting of the characters in // validBootstrapTokenChars, with the length customized by the parameter func randBytes(length int) (string, error) { <del> // len("0123456789abcdefghijklmnopqrstuvwxyz") = 36 which doesn't evenly divide // the possible values of a byte: 256 mod 36 = 4. Discard any random bytes we // read that are >= 252 so the bytes we evenly divide the character set. const maxByteValue = 252 </del> var ( <del> b     byte err   error </del> token = make([]byte, length) <ins> max   = new(big.Int).SetUint64(uint64(len(validBootstrapTokenChars))) </ins> ) <del> reader := bufio.NewReaderSize(rand.Reader, length*2) </del> for i := range token { <del> for { if b, err = reader.ReadByte(); err != nil { return "", err } if b < maxByteValue { break } </del> <ins> val, err := rand.Int(rand.Reader, max) if err != nil { return "", fmt.Errorf("could not generate random integer: %w", err) </ins> } <del> token[i] = validBootstrapTokenChars[int(b)%len(validBootstrapTokenChars)] </del> <ins> // Use simple operations in constant-time to obtain a byte in the a-z,0-9 // character range x := val.Uint64() res := x + 48 + (39 & ((9 - x) >> 8)) token[i] = byte(res) </ins> } return string(token), nil

return fmt.Sprintf("%s.%s", id, secret) } <del> // IsValidBootstrapToken returns whether the given string is valid as a Bootstrap Token and // in other words satisfies the BootstrapTokenRegexp </del> <ins> // IsValidBootstrapToken returns whether the given string is valid as a Bootstrap Token. // Avoid using BootstrapTokenRegexp.MatchString(token) and instead perform constant-time // comparisons on the secret. </ins> func IsValidBootstrapToken(token string) bool { <del> return BootstrapTokenRegexp.MatchString(token) </del> <ins> // Must be exactly two strings separated by "." t := strings.Split(token, ".") if len(t) != 2 { return false } // Validate the ID: t[0] // Using a Regexp for it is safe because the ID is public already if !BootstrapTokenIDRegexp.MatchString(t[0]) { return false } // Validate the secret with constant-time: t[1] secret := t[1] if len(secret) != api.BootstrapTokenSecretBytes { // Must be an exact size return false } for i := range secret { c := int(secret[i]) notDigit := (c < 48 || c > 57)   // Character is not in the 0-9 range notLetter := (c < 97 || c > 122) // Character is not in the a-z range if notDigit && notLetter { return false } } return true </ins> } // IsValidBootstrapTokenID returns whether the given string is valid as a Bootstrap Token ID and