kubernetes/kubernetes · error
subject organization is not system:nodes
Error message
subject organization is not system:nodes
What it means
Returned by ValidateKubeletServingCSR / ValidateKubeletClientCSR when the CSR's Subject.Organization is not exactly the single-element slice ["system:nodes"]. Kubelet-serving and kubelet-client CSRs are strictly scoped to the system:nodes group; any other (or missing) organization is rejected.
Source
Thrown at pkg/apis/certificates/helpers.go:44
"k8s.io/apimachinery/pkg/util/sets"
)
// ParseCSR extracts the CSR from the bytes and decodes it.
func ParseCSR(pemBytes []byte) (*x509.CertificateRequest, error) {
block, _ := pem.Decode(pemBytes)
if block == nil || block.Type != "CERTIFICATE REQUEST" {
return nil, errors.New("PEM block type must be CERTIFICATE REQUEST")
}
csr, err := x509.ParseCertificateRequest(block.Bytes)
if err != nil {
return nil, err
}
return csr, nil
}
var (
organizationNotSystemNodesErr = fmt.Errorf("subject organization is not system:nodes")
commonNameNotSystemNode = fmt.Errorf("subject common name does not begin with system:node:")
dnsOrIPSANRequiredErr = fmt.Errorf("DNS or IP subjectAltName is required")
dnsSANNotAllowedErr = fmt.Errorf("DNS subjectAltNames are not allowed")
emailSANNotAllowedErr = fmt.Errorf("Email subjectAltNames are not allowed")
ipSANNotAllowedErr = fmt.Errorf("IP subjectAltNames are not allowed")
uriSANNotAllowedErr = fmt.Errorf("URI subjectAltNames are not allowed")
)
var (
kubeletServingRequiredUsages = sets.NewString(
string(UsageDigitalSignature),
string(UsageKeyEncipherment),
string(UsageServerAuth),
)
kubeletServingRequiredUsagesNoRSA = sets.NewString(
string(UsageDigitalSignature),
string(UsageServerAuth),
)View on GitHub (pinned to b882c60b40)
Solutions
- Set the CSR Subject.Organization to exactly []string{"system:nodes"}.
- Verify the kubelet's --bootstrap-kubeconfig and node registration config produce the correct Subject.
- Regenerate the CSR after fixing the Subject.
Example fix
// before
template := x509.CertificateRequest{
Subject: pkix.Name{CommonName: "system:node:node1", Organization: []string{"kube-system"}},
}
// after
template := x509.CertificateRequest{
Subject: pkix.Name{CommonName: "system:node:node1", Organization: []string{"system:nodes"}},
} Defensive patterns
Strategy: validation
Validate before calling
func hasSystemNodesOrg(req *x509.CertificateRequest) bool {
return reflect.DeepEqual(req.Subject.Organization, []string{"system:nodes"})
} Type guard
func isKubeletCSRSubject(req *x509.CertificateRequest) bool {
return reflect.DeepEqual(req.Subject.Organization, []string{"system:nodes"}) &&
strings.HasPrefix(req.Subject.CommonName, "system:node:")
} Try / catch
if err := certificates.ValidateKubeletServingCSR(csr, usages); err != nil {
if errors.Is(err, certificates.ErrOrgNotSystemNodes) { /* fix Subject */ }
return err
} Prevention
- Build kubelet CSR templates from a shared helper that always sets Organization=[system:nodes].
- Unit-test CSR generation against both Validate functions.
When it happens
Trigger: Calling certificates.ValidateKubeletServingCSR or ValidateKubeletClientCSR with an x509.CertificateRequest whose Subject.Organization differs from ["system:nodes"] (empty, multi-element, or a different value).
Common situations: A kubelet bootstrapping with a wrong/missing org in its CSR config; a custom CSR generator that sets O to the node's cloud group; TLS bootstrap misconfiguration in kubelet flags.
Related errors
- DNS or IP subjectAltName is required
- DNS subjectAltNames are not allowed
- usages did not match %v
- Email subjectAltNames are not allowed
- IP subjectAltNames are not allowed
AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07).
Data as JSON: /api/errors/c2a9d95305f60a31.
Report an issue: GitHub.