{"record":{"id":"cae0cc11fe74ed8b","repo":"k3s-io/k3s","slug":"cannot-manage-secrets-encryption-on-non-control-pl","errorCode":null,"errorMessage":"cannot manage secrets encryption on non control-plane node %s","messagePattern":"cannot manage secrets encryption on non control-plane node (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"pkg/server/handlers/secrets-encrypt.go","lineNumber":522,"sourceCode":"\t\t},\n\t}\n\tif keyType == secretsencrypt.AESCBCProvider {\n\t\tkeys.AESCBCKeys = append(keys.AESCBCKeys, newKey...)\n\t} else if keyType == secretsencrypt.SecretBoxProvider {\n\t\tkeys.SBKeys = append(keys.SBKeys, newKey...)\n\t}\n\tlogrus.Infoln(\"Adding secrets-encryption key: \", newKey)\n\treturn nil\n}\n\nfunc getEncryptionHashAnnotation(core core.Interface) (string, string, error) {\n\tnodeName := os.Getenv(\"NODE_NAME\")\n\tnode, err := core.V1().Node().Get(nodeName, metav1.GetOptions{})\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tif _, ok := node.Labels[util.ControlPlaneRoleLabelKey]; !ok {\n\t\treturn \"\", \"\", fmt.Errorf(\"cannot manage secrets encryption on non control-plane node %s\", nodeName)\n\t}\n\tif ann, ok := node.Annotations[secretsencrypt.EncryptionHashAnnotation]; ok {\n\t\tsplit := strings.Split(ann, \"-\")\n\t\tif len(split) != 2 {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"invalid annotation %s found on node %s\", ann, nodeName)\n\t\t}\n\t\treturn split[0], split[1], nil\n\t}\n\treturn \"\", \"\", fmt.Errorf(\"missing annotation on node %s\", nodeName)\n}\n\n// verifyRotateKeysSupport checks that the k3s version is at least v1.28.0 on all control-plane nodes\nfunc verifyRotateKeysSupport(core core.Interface) error {\n\tlabelSelector := labels.Set{util.ControlPlaneRoleLabelKey: \"true\"}.String()\n\tnodes, err := core.V1().Node().List(metav1.ListOptions{LabelSelector: labelSelector})\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/server/handlers/secrets-encrypt.go#L504-L540","documentation":"Before any secrets-encryption operation, k3s reads its own Node object (from the NODE_NAME environment variable) and requires the node-role.kubernetes.io/control-plane label. This label marks nodes allowed to hold and rotate encryption state; without it the node is treated as a non control-plane node and secrets-encrypt management is refused.","triggerScenarios":"Running 'k3s secrets-encrypt ...' (or the equivalent API call) on a machine whose Node object lacks the control-plane label: an agent-only host, a server whose label was removed/renamed, or a server started with --node-label that overwrote role labels. NODE_NAME pointing at the wrong node produces the same refusal.","commonSituations":"SSHing into the wrong host (an agent) to run secrets-encrypt; labels stripped by external tooling or manually with kubectl; NODE_NAME inherited from a container/supervisor environment that does not match the actual node name.","solutions":["Run secrets-encrypt commands on a control-plane (server) node and confirm with: kubectl get node <name> --show-labels | grep node-role.kubernetes.io/control-plane.","If the label was lost on a genuine server, restore it: kubectl label node <name> node-role.kubernetes.io/control-plane=true (then verify NODE_NAME correctness).","Verify NODE_NAME resolves to the node you are on when k3s runs under a custom unit/container: echo $NODE_NAME.","If your topology deliberately uses non-standard role labels, stick to running encryption ops from a node that carries the standard label."],"exampleFix":"# before: on agent host\nk3s secrets-encrypt status  # -> cannot manage secrets encryption on non control-plane node\n\n# after: on a server\necho $NODE_NAME && kubectl get node $NODE_NAME -L node-role.kubernetes.io/control-plane\nk3s secrets-encrypt status","handlingStrategy":"validation","validationCode":"// Before running secrets-encrypt commands, verify this host is control-plane\nnode, err := clientset.CoreV1().Nodes().Get(os.Getenv(\"NODE_NAME\"), metav1.GetOptions{})\nif err != nil { log.Fatal(err) }\nif _, ok := node.Labels[\"node-role.kubernetes.io/control-plane\"]; !ok {\n    log.Fatal(\"run secrets-encryption operations on a control-plane node\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run secrets-encrypt only on server nodes","Verify NODE_NAME correctness in containerized k3s deployments","Protect role labels from cleanup automation"],"tags":["secrets-encryption","nodes","labels","rbac"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}