-
Notifications
You must be signed in to change notification settings - Fork 41.2k
Description
This issue was reported in the Kubernetes Security Audit Report
Description
Many services in Kubernetes use questionable default functions, such as insecure random number generation or dangerous temporary file creation.
In regards to random number generation, many services, including kubelet, api-server, kube-scheduler, kube-proxy, seed the random number generator in the following manner.
rand.Seed(time.Now().UnixNano())
Figure 27.1: The common method of seeding rand with time in Kubernetes.
Generally this is okay. The code properly uses crypto/rand for cryptographic operations like key generations. No cryptographic primitives were observed incorrectly using math/rand.
However, due to this seeding, certain identifiers are predictable and simplify aspects of an exploitation chain. In Figure 33.2, the node is assigned a random name that could be guessable to an attacker who knows uptime information.
func (kubemarkController *KubemarkController) addNodeToNodeGroup(nodeGroup string) error {
node := kubemarkController.nodeTemplate.DeepCopy()
...
node.Name = fmt.Sprintf("%s-%d", nodeGroup, kubemarkController.rand.Int63())
...
client.CoreV1().ReplicationControllers(node.Namespace).Create(node)
}
Figure 27.2: An example of using time-seeded values to add a node to a group.
Another concerning function was found in the kubectl create --edit command, which creates a temporary file to edit objects before creation. This temporary file is created via a custom tempFile function (Figure 33.3) called by LaunchTempFile (Figure 33.4). It is possible to create all possible temporary files that would be used, leading to the kubectl create --edit command to fail.
There is also a potential race condition in LaunchTempFile between closing the file and opening it later in the editor. However, since the file is created with 0600 permissions, this appears to be a non-issue.
func tempFile(prefix, suffix string) (f *os.File, err error) {
dir := os.TempDir()
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+randSeq(5)+suffix)
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if os.IsExist(err) {
continue
}
break
}
return
}
Figure 27.3: The tempFile function definition.
func (e Editor) LaunchTempFile(prefix, suffix string, r io.Reader) ([]byte, string, error) {
f, err := tempFile(prefix, suffix)
if err != nil {
return nil, "", err
}
defer f.Close()
path := f.Name()
if _, err := io.Copy(f, r); err != nil {
os.Remove(path)
return nil, path, err
}
// This file descriptor needs to close so the next process (Launch) can claim it.
f.Close()
if err := e.Launch(path); err != nil {
return nil, path, err
}
bytes, err := ioutil.ReadFile(path)
return bytes, path, err
}
Figure 27.4: The LaunchTempFile function definition.
Exploit Scenario
If an attacker needs to know the name or identifier of a service, Pod, or node that is infeasible to brute force, the attacker may be able to deduce the uptime from the current environment and enumerate possible seeds, narrowing the space of possible names and identifiers.
Regarding the tempFile, the attacker can create all possible temporary files (36**5 = 60466176), preventing the kubectl create --edit from creating the temporary file.
Recommendation
Short term, seed the random number generator using a less predictable seed.
Long term, investigate whether the standard library ioutil.TempFile function would be a viable replacement for the current tempFile implementation. Ensure appropriate use of math/rand and crypto/rand, and ensure correct random number generator seeding.
Anything else we need to know?:
See #81146 for current status of all issues created from these findings.
The vendor gave this issue an ID of TOB-K8S-033 and it was finding 30 of the report.
The vendor considers this issue Low Severity.
To view the original finding, begin on page 75 of the Kubernetes Security Review Report
Environment:
- Kubernetes version: 1.13.4
Metadata
Metadata
Assignees
Labels
Type
Projects
Status