Press "Enter" to skip to content

【故障复盘】Elasticsearch 集群证书过期,节点重启后失联的紧急救援实录

1. 故障背景

我们维护了一个由 3 个节点组成的 Elasticsearch 集群(版本为 7.x/8.x),开启了 X-Pack 安全认证(TLS 通信)。

故障现象:
日常维护中,我重启了其中一个节点(es-node-01),结果该节点启动后无法加入集群。查看集群状态,另外两个节点(es-node-02, es-node-03)依然处于运行状态,但集群状态变为 Yellow/Red,且缺少了一个节点。

2. 问题排查

查看 es-node-01 的启动日志,发现了大量报错,核心堆栈如下:

[WARN ][o.e.t.TcpTransport] [es-node-01] exception caught on transport layer ..., closing connection
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: PKIX path validation failed: validity check failed
...
Caused by: java.security.cert.CertificateExpiredException: NotAfter: Sun Nov 19 18:05:03 CST 2023

关键信息提取:

  • PKIX path validation failed: 证书路径验证失败。
  • CertificateExpiredException: NotAfter: ... 2023: 最致命的错误。证书在 2023 年就已经过期了,而当前时间是 2026 年。

3. 深度分析:为什么另外两个节点还活着?

这是一个典型的**“僵尸集群”**状态。

  • 存活节点(Node 02/03):它们之间的 TCP 长连接是在证书过期之前建立的。只要连接不断开,通信就能维持。
  • 重启节点(Node 01):重启意味着 TCP 连接断开。当它尝试重新连接集群时,必须进行 SSL 握手。此时系统检查证书有效期,发现已过期,因此直接拒绝连接。

面临的困境(死锁):
如果只给 Node 01 换新证书,它去连 Node 02,Node 02 出示的还是旧证书,握手依然失败。
如果此时重启 Node 02/03,它们也会立刻报错起不来。

结论: 必须申请停机窗口,进行全集群重启(Full Cluster Restart),一次性替换所有节点的证书。

4. 解决方案

4.1 环境确认

检查 elasticsearch.yml 配置,确认当前使用的是 PEM 格式(.crt, .key)证书:

xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.key: certs/node.key
xpack.security.transport.ssl.certificate: certs/node.crt
xpack.security.transport.ssl.certificate_authorities: [ "certs/ca.crt" ]

4.2 制作新证书

在任意节点上,准备一个 instances.yml 文件,定义集群所有节点信息:

instances:
  - name: "es-node-01" 
    ip: ["10.x.x.1"]
  - name: "es-node-02"
    ip: ["10.x.x.2"]
  - name: "es-node-03"
    ip: ["10.x.x.3"]

使用 elasticsearch-certutil 工具重新生成 CA 和节点证书(有效期设置为 10 年,避免短期再次过期):

# 1. 生成新的 CA (根证书)
./bin/elasticsearch-certutil ca --pem --out ca.zip --days 3650
unzip ca.zip -d ca_temp

# 2. 基于新 CA 生成节点证书
./bin/elasticsearch-certutil cert --pem --ca-cert ca_temp/ca/ca.crt --ca-key ca_temp/ca/ca.key --in instances.yml --out certs.zip --days 3650
unzip certs.zip -d new_certs

4.3 替换与重启(关键步骤)

为了打破证书信任死锁,我执行了以下操作:

  1. 停止集群:停止 Node 02 和 Node 03 的服务(Node 01 已经是停止状态)。
  2. 分发证书:将生成的 ca.crt 以及各节点对应的 .crt.key 文件分发到三台服务器的 config/certs/ 目录下,覆盖原文件
    • 注意:文件名必须与配置文件中定义的一致。
  3. 依次启动
    • 先启动 Node 02(作为主节点候选)。
    • 观察日志,确认无 SSL 报错,状态为 started
    • 依次启动 Node 03 和 Node 01。

5. 结果验证

所有节点启动后,查看集群节点状态:

curl -X GET "localhost:9200/_cat/nodes?v"

输出显示 3 个节点全部在线(* 表示主节点):

ip         heap.percent ram.percent cpu load_1m name
10.x.x.2   45           60          5   0.20    es-node-02 *
10.x.x.3   40           58          3   0.15    es-node-03
10.x.x.1   10           55          8   0.45    es-node-01

登录 Kibana 查看,集群状态由 Red 转为 Yellow,最终变为 Green,分片正在进行 Rebalancing(再平衡),数据同步恢复正常。

6. 经验总结

  1. 监控证书有效期:SSL 证书过期是隐形杀手,建议将证书有效期加入监控告警(如使用 Prometheus 的 ssl_exporter)。
  2. 生成证书时预留足够时间:对于内部集群,建议生成证书时使用 --days 3650(10年),减少维护成本。
  3. 冷静应对僵尸状态:当发现部分节点因证书过期无法加入时,不要试图“修补”单个节点,果断进行全集群维护才是最高效的解法。
发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注