{"record":{"id":"4e44dce79f47965f","repo":"slackhq/nebula","slug":"private-key-is-not-a-pair-with-public-key-in-nebul","errorCode":null,"errorMessage":"private key is not a pair with public key in nebula cert: %w","messagePattern":"private key is not a pair with public key in nebula cert: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pki.go","lineNumber":423,"sourceCode":"\t\t}\n\n\t\tif v1.Curve() != v2.Curve() {\n\t\t\treturn nil, util.NewContextualError(\"v1 and v2 curve are not the same, ignoring\", nil, nil)\n\t\t}\n\n\t\tif v1.Networks()[0] != v2.Networks()[0] {\n\t\t\treturn nil, util.NewContextualError(\"v1 and v2 networks are not the same\", nil, nil)\n\t\t}\n\n\t\tcs.initiatingVersion = dv\n\t}\n\n\tif v1 != nil {\n\t\tif pkcs11backed {\n\t\t\t//NOTE: We do not currently have a method to verify a public private key pair when the private key is in an hsm\n\t\t} else {\n\t\t\tif err := v1.VerifyPrivateKey(privateKeyCurve, privateKey); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"private key is not a pair with public key in nebula cert: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tv1hs, err := v1.MarshalForHandshakes()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error marshalling v1 certificate for handshake: %w\", err)\n\t\t}\n\t\tncs, err := newCipherSuite(v1.Curve(), pkcs11backed, cipher, fips140.Enforced())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcs.v1Cert = v1\n\t\tcs.v1Credential = handshake.NewCredential(v1, v1hs, privateKey, ncs)\n\n\t\tif cs.initiatingVersion == 0 {\n\t\t\tcs.initiatingVersion = cert.Version1\n\t\t}\n\t}","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/pki.go#L405-L441","documentation":"newCertState calls v1.VerifyPrivateKey(curve, privateKey) and the private key in pki.key does not correspond to the public key inside the v1 nebula certificate. The %w wraps the underlying mismatch error.","triggerScenarios":"newCertState (from newCertStateFromConfig / TestNewFirewallFromConfig): a v1 certificate is present and the loaded pki.key fails VerifyPrivateKey — key and cert belong to different identities.","commonSituations":"Replaced pki.cert but not pki.key (or vice versa); files from different hosts mixed by config management; wrong key file path pointing to another node's key.","solutions":["Re-issue the host certificate signed from the existing pki.key (nebula-cert sign -key pki.key ...) so cert and key match","Or restore the pki.key that pairs with the current certificate","Confirm pairing by comparing public keys: nebula-cert print -path pki.cert vs the key's public key"],"exampleFix":"// before: cert for host A + key for host B\npki:\n  cert: /etc/nebula/hostA.crt\n  key:  /etc/nebula/hostB.key\n// after: regenerate cert from the key you keep\nnebula-cert sign -ca-crt ca.crt -ca-key ca.key -name hostB -ip 10.0.0.2/24 -key /etc/nebula/pki.key -out-crt /etc/nebula/pki.cert","handlingStrategy":"validation","validationCode":"// verify key/cert pairing before starting nebula\nfunc keyMatchesCert(certPath, keyPath string) error {\n    crtPEM, _ := os.ReadFile(certPath)\n    keyPEM, _ := os.ReadFile(keyPath)\n    crt, _, err := cert.UnmarshalCertificateFromPEM(certPEM); if err != nil { return err }\n    _, _, curve, err := cert.UnmarshalPrivateKeyFromPEM(keyPEM); if err != nil { return err }\n    return crt.VerifyPrivateKey(curve, keyPEM)\n}","typeGuard":null,"tryCatchPattern":"if err := reloadCerts(); err != nil {\n    if strings.Contains(err.Error(), \"private key is not a pair\") {\n        log.Fatalf(\"pki.cert and pki.key do not match; re-issue the certificate for this key: %v\", err)\n    }\n    return err\n}","preventionTips":["Always deploy cert and key as one atomic unit (same directory, same commit)","Never reuse a cert file from another host","Verify pairing with nebula-cert print and a key public-key dump during deployment"],"tags":["pki","keypair","certificate"],"backgroundTag":"private-key-public-key-mismatch","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"}