slackhq/nebula · error
host certificate is a CA certificate
Error message
host certificate is a CA certificate
What it means
loadCertificate rejects certificates where c.IsCA() is true: a CA certificate is a signing identity, not a host identity, and cannot be used as pki.cert. This prevents operators from accidentally booting a node with the CA's own certificate and key material.
Source
Thrown at pki.go:534
return
}
func loadCertificate(b []byte) (cert.Certificate, []byte, error) {
c, b, err := cert.UnmarshalCertificateFromPEM(b)
if err != nil {
return nil, b, fmt.Errorf("error while unmarshaling pki.cert: %w", err)
}
if c.Expired(time.Now()) {
return nil, b, fmt.Errorf("nebula certificate for this host is expired")
}
if len(c.Networks()) == 0 {
return nil, b, fmt.Errorf("no networks encoded in certificate")
}
if c.IsCA() {
return nil, b, fmt.Errorf("host certificate is a CA certificate")
}
return c, b, nil
}
func loadCAPoolFromConfig(l *slog.Logger, c *config.C) (*cert.CAPool, error) {
caPathOrPEM := c.GetString("pki.ca", "")
if caPathOrPEM == "" {
return nil, errors.New("no pki.ca path or PEM data provided")
}
var caReader io.ReadCloser
var err error
if strings.Contains(caPathOrPEM, "-----BEGIN") {
caReader = io.NopCloser(strings.NewReader(caPathOrPEM))
} else {
caReader, err = os.Open(caPathOrPEM)View on GitHub (pinned to dd8f660c0a)
Solutions
- Point pki.cert at the host certificate issued by the CA, not ca.crt
- If no host cert exists, sign one: 'nebula-cert sign -ca-cpath ca.crt -ca-kpath ca.key -name host -ip 10.0.0.5'
- Keep pki.ca set to ca.crt and pki.cert set to host.crt in the config
Example fix
// before pki: ca: /etc/nebula/ca.crt cert: /etc/nebula/ca.crt # CA cert reused as host cert // after pki: ca: /etc/nebula/ca.crt cert: /etc/nebula/host.crt # host cert signed by the CA
Defensive patterns
Strategy: validation
Validate before calling
c, _, err := cert.UnmarshalCertificateFromPEM(certBytes)
if err == nil && c.IsCA() {
return fmt.Errorf("%s is a CA cert; use the host cert for pki.cert", path)
} Type guard
func isHostCert(c cert.Certificate) bool { return !c.IsCA() } Try / catch
if err := startNebula(); err != nil && strings.Contains(err.Error(), "is a CA certificate") {
return fmt.Errorf("pki.cert must be a host cert, not ca.crt: %w", err)
} Prevention
- Name files unambiguously: ca.crt vs <host>.crt
- Restrict CA key/cert distribution; hosts only need ca.crt in pki.ca
- Config-lint that pki.cert != pki.ca
- Sign host certs with 'nebula-cert sign', never reuse 'nebula-cert ca' output as identity
When it happens
Trigger: newCertStateFromConfig is given a certificate produced by 'nebula-cert ca' (IsCA set) instead of one produced by 'nebula-cert sign'.
Common situations: Config copy-paste mixup where pki.cert and pki.ca both point at ca.crt; packaging scripts that bundle the wrong file as the host cert.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- v1 certificate already found in pki.cert
- v2 certificate already found in pki.cert
- error while unmarshaling pki.cert: %w
- no networks encoded in certificate
- error while adding CA certificate to CA trust store: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/9b9540e1915d8940.
Report an issue: GitHub.