{"record":{"id":"8ab83d51cba1b9a3","repo":"slackhq/nebula","slug":"certificate-expires-after-signing-certificate","errorCode":null,"errorMessage":"certificate expires after signing certificate","messagePattern":"certificate expires after signing certificate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/ca_pool.go","lineNumber":290,"sourceCode":"\ti := 0\n\tfor k := range ncp.CAs {\n\t\tfp[i] = k\n\t\ti++\n\t}\n\n\treturn fp\n}\n\n// CheckCAConstraints returns an error if the sub certificate violates constraints present in the signer certificate.\nfunc CheckCAConstraints(signer Certificate, sub Certificate) error {\n\treturn checkCAConstraints(signer, sub.NotBefore(), sub.NotAfter(), sub.Groups(), sub.Networks(), sub.UnsafeNetworks())\n}\n\n// checkCAConstraints is a very generic function allowing both Certificates and TBSCertificates to be tested.\nfunc checkCAConstraints(signer Certificate, notBefore, notAfter time.Time, groups []string, networks, unsafeNetworks []netip.Prefix) error {\n\t// Make sure this cert isn't valid after the root\n\tif notAfter.After(signer.NotAfter()) {\n\t\treturn fmt.Errorf(\"certificate expires after signing certificate\")\n\t}\n\n\t// Make sure this cert wasn't valid before the root\n\tif notBefore.Before(signer.NotBefore()) {\n\t\treturn fmt.Errorf(\"certificate is valid before the signing certificate\")\n\t}\n\n\t// If the signer has a limited set of groups make sure the cert only contains a subset\n\tsignerGroups := signer.Groups()\n\tif len(signerGroups) > 0 {\n\t\tfor _, g := range groups {\n\t\t\tif !slices.Contains(signerGroups, g) {\n\t\t\t\treturn fmt.Errorf(\"certificate contained a group not present on the signing ca: %s\", g)\n\t\t\t}\n\t\t}\n\t}\n\n\t// If the signer has a limited set of ip ranges to issue from make sure the cert only contains a subset","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/ca_pool.go#L272-L308","documentation":"checkCAConstraints enforces that a signed certificate's validity window fits inside the signer's. This error means the certificate's notAfter is later than the signing CA's notAfter, i.e. the cert would outlive its issuer. It is returned both when checking existing certs (CheckCAConstraints) and when signing new ones (SignWith).","triggerScenarios":"Calling CAPool.CheckCAConstraints(signer, sub) where sub.NotAfter() is after signer.NotAfter(); or SignWith with an expiry parameter beyond the signing CA's expiration.","commonSituations":"Issuing a 10-year host certificate signed by a 1-year CA; config generators defaulting cert lifetime independently of CA lifetime; renewing the CA with a shorter validity than long-lived leaf certs.","solutions":["Shorten the certificate's notAfter to be <= the signing CA's notAfter","Renew/extend the CA certificate's validity, then re-sign","Use SignWith with an expiry computed as min(desired, signer.NotAfter())"],"exampleFix":"// before\nnc, err := ca.SignWith(pubKey, curve, opts) // opts.NotAfter after CA expiry\n// after\nexpiry := desiredExpiry\nif ca.NotAfter().Before(expiry) {\n    expiry = ca.NotAfter()\n}\nopts.NotAfter = expiry\nnc, err := ca.SignWith(pubKey, curve, opts)","handlingStrategy":"validation","validationCode":"if sub.NotAfter().After(signer.NotAfter()) {\n    return fmt.Errorf(\"cert would outlive its CA; renew CA or shorten cert validity\")\n}\nerr := pool.CheckCAConstraints(signer, sub)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set leaf cert validity well inside CA validity (e.g. CA life / 2)","Compute SignWith expiry as min(desired, ca.NotAfter())","Alert on CAs approaching expiry before issuing new certs","Review cert lifetimes in CI when generation configs change"],"tags":["certificate","validity","ca-constraints"],"backgroundTag":"certificate-validity-window-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"}