{"record":{"id":"526f81ba3c0b8d80","repo":"k3s-io/k3s","slug":"password-hash-not-found-in-node-secret","errorCode":null,"errorMessage":"password hash not found in node secret","messagePattern":"password hash not found in node secret","errorType":"http","errorClass":"passwordError","httpStatus":403,"severity":"error","filePath":"pkg/nodepassword/nodepassword.go","lineNumber":60,"sourceCode":"\nfunc errVerifyFailed() error { return &passwordError{} }\n\nfunc getSecretName(nodeName string) string {\n\treturn strings.ToLower(nodeName + \".node-password.\" + version.Program)\n}\n\nfunc (npc *nodePasswordController) verifyHash(nodeName, pass string, cached bool) error {\n\tsecret, err := npc.getSecret(nodeName, cached)\n\tif err != nil {\n\t\treturn &passwordError{node: nodeName, err: err}\n\t}\n\tif hash, ok := secret.Data[\"hash\"]; ok {\n\t\tif err := Hasher.VerifyHash(string(hash), pass); err != nil {\n\t\t\treturn &passwordError{node: nodeName, err: err}\n\t\t}\n\t\treturn nil\n\t}\n\treturn &passwordError{node: nodeName, err: errors.New(\"password hash not found in node secret\")}\n}\n\n// ensure will verify a node-password secret if it exists, otherwise it will create one\nfunc (npc *nodePasswordController) ensure(nodeName, pass string) error {\n\terr := npc.verifyHash(nodeName, pass, true)\n\tif apierrors.IsNotFound(err) {\n\t\tvar hash string\n\t\thash, err = Hasher.CreateHash(pass)\n\t\tif err != nil {\n\t\t\treturn &passwordError{node: nodeName, err: err}\n\t\t}\n\t\t_, err = npc.secrets.Create(&v1.Secret{\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName:      getSecretName(nodeName),\n\t\t\t\tNamespace: metav1.NamespaceSystem,\n\t\t\t},\n\t\t\tImmutable: ptr.To(true),\n\t\t\tData:      map[string][]byte{\"hash\": []byte(hash)},","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/nodepassword/nodepassword.go#L42-L78","documentation":"Node-password verification looks up the per-node secret in kube-system and validates the 'hash' entry with the password hasher. If the secret exists but its Data has no 'hash' key, verification cannot proceed and the mismatch is wrapped in a passwordError carrying the node name.","triggerScenarios":"The kube-system secret 'node-password-<nodename>' (or equivalent) exists but was created/modified without a hash key - e.g. applied by a manifest, mutated by an operator, or restored from a backup made by a different version.","commonSituations":"GitOps applying node-password secrets as plain data; upgrades that changed the secret schema; a node renamed so the lookup hits a stale secret.","solutions":["Delete the offending secret: kubectl -n kube-system delete secret node-password-<node> and let the controller recreate it with a proper hash.","Restart the agent on the node so ensure() re-registers the password.","If managed by manifests/GitOps, remove the node-password secret from source control - the controller owns it."],"exampleFix":"# before: secret applied without hash key (verification always fails)\nkubectl -n kube-system apply -f node-password-mynode.yaml\n# after: let the controller own it\nkubectl -n kube-system delete secret node-password-mynode\nsystemctl restart k3s-agent  # or k3s on the node","handlingStrategy":"fallback","validationCode":"// check the secret shape before verifying\nsecret, err := npc.getSecret(nodeName, true)\nif err == nil && len(secret.Data[\"hash\"]) == 0 {\n    // malformed: delete so ensure() recreates it, or repair from the node's password file\n}","typeGuard":null,"tryCatchPattern":"err := npc.ensure(nodeName, pass)\nif err != nil {\n    var pe *passwordError\n    if errors.As(err, &pe) && strings.Contains(pe.err.Error(), \"password hash not found\") {\n        // fallback: delete malformed secret and retry once so it is recreated\n    }\n}","preventionTips":["Keep node-password secrets out of GitOps/manifest management.","Validate schema after restoring clusters from backups made by other versions."],"tags":["authentication","kubernetes","secrets","node"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}