在证书未包含“客户端认证”扩展密钥用法时,使用Let's Encrypt TLS证书配置的MongoDB停止工作
我们正在使用MongoDB v8.0.17,并将其配置为使用由Let's Encrypt颁发的TLS证书。它是一个包含三个节点的副本集(ReplicaSet)集群。每个节点都在Let's Encrypt为其完全限定域名(FQDN)颁发TLS证书,使用以下MongoDB配置:
net:
tls:
mode: requireTLS
# mongodb-tls.pem contains the private key, the certificate and all intermediates (i.e. fullchain)
certificateKeyFile: /etc/mongodb/ssl/private/mongodb-tls.pem
allowConnectionsWithoutCertificates: true
现在,当某个节点上的计划任务脚本续签证书后,MongoDB开始失败,并出现如下日志信息:
{"t":{"$date":"2026-02-25T09:40:31.862+00:00"},"s":"E", "c":"NETWORK", "id":23256, "ctx":"conn170117","msg":"SSL peer certificate validation failed","attr":{"error":"SSL peer certificate validation failed: unsupported certificate purpose"}}
{"t":{"$date":"2026-02-25T09:40:31.863+00:00"},"s":"I", "c":"EXECUTOR", "id":22988, "ctx":"conn170117","msg":"Error receiving request from client. Ending connection from remote","attr":{"error":{"code":141,"codeName":"SSLHandshakeFailed","errmsg":"SSL peer certificate validation failed: unsupported certificate purpose"},"remote":"1.2.3.4:48348","connectionId":170117}}
在调查时,我发现 Let's Encrypt在去年宣布 他们将停止签发带有 X509v3 Extended Key Usage 选项 TLS Web Client Authentication 的证书。确实,我们的证书是在2026-02-18续订,这晚于2026-02-11(即公告日期之后,Let’s Encrypt的 classic ACME配置文件不再包含客户端认证EKU)。这似乎正是这里出问题的根本原因。看起来MongoDB会使用服务器的TLS证书,在另一台ReplicaSet节点上也进行客户端证书认证,而这现在已被禁止作为证书的用途。
Let’s Encrypt确实创建了一个 tlsclient 配置文件,其中包含Client Authentication EKU。然而,该配置文件也将于2026-05-13终止存在。
因此,我在想我们如何解决这个问题?现在不再能够依赖Let’s Encrypt签发具备客户端认证能力的证书。那么MongoDB是否有选项来进行不同的集群间认证,或类似的方案?
解决方案
我猜你的问题是以下两种问题的组合:
- Let’s Encrypt不再添加
extendedKeyUsage=clientAuth - MongoDB服务器忽略对传入连接的
extendedKeyUsage设置——这一行为最近有所改变。
其实,我才是祸首。对不起 😏,请参见 extendedKeyUsage not honored in x509 certificates
关于 net.tls.clusterFile 的文档说明如下:
If
net.tls.clusterFiledoes not specify the.pemfile for internal cluster authentication, the cluster uses the.pemfile specified in thenet.tls.certificateKeyFilesetting。
所以,你并没有指定 clusterFile,因此mongod出站连接使用 certificateKeyFile 证书。然而,这是一种 serverAuth,现在不再被接受。我认为你必须设置 tlsWithholdClientCertificate: true,请参见 tlsWithholdClientCertificate。
而且你已经设置了 net.tls.allowConnectionsWithoutCertificates: true。