k3s-io/k3s · error
cannot manage secrets encryption on non control-plane node %
Error message
cannot manage secrets encryption on non control-plane node %s
What it means
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.
Source
Thrown at pkg/server/handlers/secrets-encrypt.go:522
},
}
if keyType == secretsencrypt.AESCBCProvider {
keys.AESCBCKeys = append(keys.AESCBCKeys, newKey...)
} else if keyType == secretsencrypt.SecretBoxProvider {
keys.SBKeys = append(keys.SBKeys, newKey...)
}
logrus.Infoln("Adding secrets-encryption key: ", newKey)
return nil
}
func getEncryptionHashAnnotation(core core.Interface) (string, string, error) {
nodeName := os.Getenv("NODE_NAME")
node, err := core.V1().Node().Get(nodeName, metav1.GetOptions{})
if err != nil {
return "", "", err
}
if _, ok := node.Labels[util.ControlPlaneRoleLabelKey]; !ok {
return "", "", fmt.Errorf("cannot manage secrets encryption on non control-plane node %s", nodeName)
}
if ann, ok := node.Annotations[secretsencrypt.EncryptionHashAnnotation]; ok {
split := strings.Split(ann, "-")
if len(split) != 2 {
return "", "", fmt.Errorf("invalid annotation %s found on node %s", ann, nodeName)
}
return split[0], split[1], nil
}
return "", "", fmt.Errorf("missing annotation on node %s", nodeName)
}
// verifyRotateKeysSupport checks that the k3s version is at least v1.28.0 on all control-plane nodes
func verifyRotateKeysSupport(core core.Interface) error {
labelSelector := labels.Set{util.ControlPlaneRoleLabelKey: "true"}.String()
nodes, err := core.V1().Node().List(metav1.ListOptions{LabelSelector: labelSelector})
if err != nil {
return err
}View on GitHub (pinned to 6ba341e396)
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.
Example fix
# before: on agent host k3s secrets-encrypt status # -> cannot manage secrets encryption on non control-plane node # after: on a server echo $NODE_NAME && kubectl get node $NODE_NAME -L node-role.kubernetes.io/control-plane k3s secrets-encrypt status
Defensive patterns
Strategy: validation
Validate before calling
// Before running secrets-encrypt commands, verify this host is control-plane
node, err := clientset.CoreV1().Nodes().Get(os.Getenv("NODE_NAME"), metav1.GetOptions{})
if err != nil { log.Fatal(err) }
if _, ok := node.Labels["node-role.kubernetes.io/control-plane"]; !ok {
log.Fatal("run secrets-encryption operations on a control-plane node")
} Prevention
- Run secrets-encrypt only on server nodes
- Verify NODE_NAME correctness in containerized k3s deployments
- Protect role labels from cleanup automation
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to parse kubelet version %s: %v
- unable to enable/disable secrets encryption, unknown configu
- method not allowed
- prepare does not support secretbox key type, use rotate-keys
- rotate does not support secretbox key type, use rotate-keys
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/cae0cc11fe74ed8b.
Report an issue: GitHub.