Loading HuntDB...

kubeadm logs tokens before deleting them

Low
K
Kubernetes
Submitted None
Reported by mlevesquedion

Vulnerability Details

Technical details and impact analysis

Insufficiently Protected Credentials
Report Submission Form ## Summary: `kubeabdm`'s `delete` command takes as input either a bootstrap token ID, or a full token. Before determining whether the input is just an id or a full token, `kubeadm` logs the input using `klog`. If the deletion fails, the token would remain valid. An attacker who has access to the logs could use it to perform actions that require a bootstrap token, such as creating a cluster or joining nodes to an existing cluster. ## Kubernetes Version: The vulnerable code is present in kubernetes 1.19. The specific line that contains the call to `klog` was last edited on 2019-03-24. ## Steps To Reproduce: The vulnerable code is in the `github.com/kubernetes` repository, under `kubernetes/cmd/kubeadm/app/cmd/token.go`, at line `423`. Here is the whole function: ```go // RunDeleteTokens removes a bootstrap tokens from the server. func RunDeleteTokens(out io.Writer, client clientset.Interface, tokenIDsOrTokens []string) error { for _, tokenIDOrToken := range tokenIDsOrTokens { // Assume this is a token id and try to parse it tokenID := tokenIDOrToken klog.V(1).Infof("[token] parsing token %q", tokenIDOrToken) // POTENTIAL LEAK HERE if !bootstraputil.IsValidBootstrapTokenID(tokenIDOrToken) { // Okay, the full token with both id and secret was probably passed. Parse it and extract the ID only bts, err := kubeadmapiv1beta2.NewBootstrapTokenString(tokenIDOrToken) if err != nil { return errors.Errorf("given token %q didn't match pattern %q or %q", tokenIDOrToken, bootstrapapi.BootstrapTokenIDPattern, bootstrapapi.BootstrapTokenIDPattern) } tokenID = bts.ID } tokenSecretName := bootstraputil.BootstrapTokenSecretName(tokenID) klog.V(1).Infof("[token] deleting token %q", tokenID) if err := client.CoreV1().Secrets(metav1.NamespaceSystem).Delete(context.TODO(), tokenSecretName, metav1.DeleteOptions{}); err != nil { return errors.Wrapf(err, "failed to delete bootstrap token %q", tokenID) } fmt.Fprintf(out, "bootstrap token %q deleted\n", tokenID) } return nil } ``` And here's the definition of the kubeadm command that calls that function: ```go deleteCmd := &cobra.Command{ Use: "delete [token-value] ...", DisableFlagsInUseLine: true, Short: "Delete bootstrap tokens on the server", Long: dedent.Dedent(` This command will delete a list of bootstrap tokens for you. The [token-value] is the full Token of the form "[a-z0-9]{6}.[a-z0-9]{16}" or the Token ID of the form "[a-z0-9]{6}" to delete. `), RunE: func(tokenCmd *cobra.Command, args []string) error { if len(args) < 1 { return errors.Errorf("missing subcommand; 'token delete' is missing token of form %q", bootstrapapi.BootstrapTokenIDPattern) } kubeConfigFile = cmdutil.GetKubeConfigPath(kubeConfigFile) client, err := getClientset(kubeConfigFile, dryRun) if err != nil { return err } return RunDeleteTokens(out, client, args) }, } ``` ## Supporting Material/References: None. ## Impact An attacker who obtains a bootstrap token from the logs could use it to authenticate with `kubeadm` and create a new cluster or join nodes to an existing cluster, e.g. to use computing resources. An attacker could also perform other actions using `kubeadm`, e.g. listing or deleting other tokens.

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Submitted

Weakness

Insufficiently Protected Credentials