{"record":{"id":"3e1ee75d9790ec1a","repo":"hashicorp/nomad","slug":"invalid-certificate-s-not-in-expected-s","errorCode":null,"errorMessage":"invalid certificate: %s not in expected %s","messagePattern":"invalid certificate: (.+?) not in expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/auth/auth.go","lineNumber":443,"sourceCode":"}\n\n// validateCertificateForNames returns true if the certificate is valid for any\n// of the given domain names.\nfunc validateCertificateForNames(cert *x509.Certificate, expectedNames []string) (bool, error) {\n\tif cert == nil {\n\t\treturn false, nil\n\t}\n\n\tvalidNames := []string{cert.Subject.CommonName}\n\tvalidNames = append(validNames, cert.DNSNames...)\n\n\tfor _, expectedName := range expectedNames {\n\t\tif slices.Contains(validNames, expectedName) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, fmt.Errorf(\"invalid certificate: %s not in expected %s\",\n\t\tstrings.Join(validNames, \", \"),\n\t\tstrings.Join(expectedNames, \", \"))\n\n}\n\n// IdentityToACLClaim returns an ACLClaim suitable for checking permissions\nfunc IdentityToACLClaim(ai *structs.AuthenticatedIdentity, store *state.StateStore) *acl.ACLClaim {\n\tif ai == nil || ai.Claims == nil {\n\t\treturn nil\n\t}\n\n\tvar group string\n\talloc, err := store.AllocByID(nil, ai.Claims.AllocationID)\n\tif err != nil {\n\t\t// we should never hit this error, but if we did the caller would get a\n\t\t// nil claim and auth will fail\n\t\treturn nil\n\t}","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/auth/auth.go#L425-L461","documentation":"validateCertificateForNames checks that the TLS certificate presented by the peer contains at least one of the names the verifier expects. If none of the certificate's valid names (SANs/CNs) intersect the expected names, it fails with 'invalid certificate: <cert names> not in expected <expected names>'. This is mTLS name verification rejecting a certificate issued for different identities.","triggerScenarios":"A TLS (mTLS) handshake/verification where the peer's certificate SAN/CN list does not include any of the expected service names — e.g. checking a cert whose names are 'client.region1.nomad' against expected 'server.region1.nomad'.","commonSituations":"Certificate generated without the required SANs; using a client cert where a server cert is expected; region/hostname changed after cert issuance; CA template (e.g. Vault PKI) misconfigured with wrong role names.","solutions":["Reissue the certificate with SANs/CNs covering the expected names shown in the error message","Fix the PKI/CA role template so issued certs include the required Nomad service names (e.g. server.<region>.nomad, client.<region>.nomad)","Ensure the correct certificate (server vs client) is configured for the given connection direction","If the expected names changed (region rename, host change), reissue certs or update the expected-name configuration"],"exampleFix":"// before: cert issued without expected SAN\n// openssl req ... -addext 'subjectAltName=DNS:localhost' // insufficient\n// after: include expected Nomad names\n// openssl req ... -addext 'subjectAltName=DNS:server.region1.nomad,DNS:client.global.nomad'","handlingStrategy":"validation","validationCode":"cert, err := tls.X509KeyPair(certPEM, keyPEM)\nx509Cert, _ := x509.ParseCertificate(cert.Certificate[0])\nexpected := []string{\"server.region1.nomad\", \"client.region1.nomad\"}\nfor _, name := range x509Cert.DNSNames {\n    if slices.Contains(expected, name) { return nil }\n}\nreturn errors.New(\"cert SANs do not include expected Nomad names\")","typeGuard":"func certCoversExpectedNames(cert *x509.Certificate, expected []string) bool {\n    names := append(cert.DNSNames, cert.Subject.CommonName)\n    for _, e := range expected {\n        if slices.Contains(names, e) { return true }\n    }\n    return false\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"invalid certificate:\") {\n    // parse the 'not in expected' list from the message and reissue the cert\n    return fmt.Errorf(\"reissue certificate with required SANs: %w\", err)\n}","preventionTips":["Issue certificates with all required Nomad service SANs (server.<region>.nomad, client.<region>.nomad)","Validate issued certs against expected names at provisioning time, before deployment","Reissue certificates whenever region or host names change","Use a managed PKI (e.g. Vault) role template that guarantees the SAN set"],"tags":["nomad","tls","mtls","certificate","x509"],"backgroundTag":"certificate-hostname-mismatch","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}