{"record":{"id":"91c7db374a632411","repo":"slackhq/nebula","slug":"no-pki-ca-path-or-pem-data-provided","errorCode":null,"errorMessage":"no pki.ca path or PEM data provided","messagePattern":"no pki\\.ca path or PEM data provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pki.go","lineNumber":543,"sourceCode":"\tif c.Expired(time.Now()) {\n\t\treturn nil, b, fmt.Errorf(\"nebula certificate for this host is expired\")\n\t}\n\n\tif len(c.Networks()) == 0 {\n\t\treturn nil, b, fmt.Errorf(\"no networks encoded in certificate\")\n\t}\n\n\tif c.IsCA() {\n\t\treturn nil, b, fmt.Errorf(\"host certificate is a CA certificate\")\n\t}\n\n\treturn c, b, nil\n}\n\nfunc loadCAPoolFromConfig(l *slog.Logger, c *config.C) (*cert.CAPool, error) {\n\tcaPathOrPEM := c.GetString(\"pki.ca\", \"\")\n\tif caPathOrPEM == \"\" {\n\t\treturn nil, errors.New(\"no pki.ca path or PEM data provided\")\n\t}\n\n\tvar caReader io.ReadCloser\n\tvar err error\n\n\tif strings.Contains(caPathOrPEM, \"-----BEGIN\") {\n\t\tcaReader = io.NopCloser(strings.NewReader(caPathOrPEM))\n\t} else {\n\t\tcaReader, err = os.Open(caPathOrPEM)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to read pki.ca file %s: %s\", caPathOrPEM, err)\n\t\t}\n\t}\n\tdefer caReader.Close()\n\n\tcaPool, err := cert.NewCAPoolFromPEMReader(caReader)\n\tif errors.Is(err, cert.ErrExpired) {\n\t\tvar expired int","sourceCodeStart":525,"sourceCodeEnd":561,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/pki.go#L525-L561","documentation":"loadCAPoolFromConfig builds the CA trust pool from the 'pki.ca' setting. If the string is empty there is no CA material to load, so it fails immediately. Every certificate chain must verify against a CA, so this is required config.","triggerScenarios":"reloadCAPool → loadCAPoolFromConfig where c.GetString(\"pki.ca\", \"\") is \"\" — pki.ca missing or empty in config.","commonSituations":"Config template omits the CA entry; ca.crt never provisioned to the host; env variable holding the CA path unset; key renamed in a customized config (e.g. pki.ca_path).","solutions":["Set pki.ca to the CA bundle path or inline PEM ('-----BEGIN CERTIFICATE-----') signed by nebula-ca.","Verify the ca.crt exists at the configured path and is readable.","Check that the value isn't an empty env expansion when templating."],"exampleFix":"// before\npki:\n  cert: /etc/nebula/host.crt\n  key: /etc/nebula/host.key\n// after\npki:\n  cert: /etc/nebula/host.crt\n  key: /etc/nebula/host.key\n  ca: /etc/nebula/ca.crt","handlingStrategy":"validation","validationCode":"if c.GetString(\"pki.ca\", \"\") == \"\" {\n    return errors.New(\"config is missing pki.ca: set the CA bundle path or inline PEM\")\n}","typeGuard":null,"tryCatchPattern":"if err := reloadCAPool(l, c); err != nil {\n    if strings.Contains(err.Error(), \"no pki.ca\") {\n        log.Fatal(\"nebula config has no pki.ca set\")\n    }\n}","preventionTips":["Always provision ca.crt alongside host.crt/key and reference it in config","Validate the trio (cert/key/ca) in a preflight config check","Keep the CA on stable storage; don't rely on env-injected values that can be empty"],"tags":["pki","ca","nebula","config"],"backgroundTag":"missing-pki-ca","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}