Elasticsearch的证书过期处理方法

摘要

ES证书简介

  • Elasticsearch 8 默认情况下创建的证书只有3年有效期,过期时需要创建新的证书,为了不必要的麻烦,也可以一开始就创建一个有效期比较长的证书。

  • 在 Elasticsearch 8 的配置下,config/certs 目录通常存放的是用于安全通信的证书和密钥文件。这些文件确保了 Elasticsearch 实例之间的通讯以及与外部客户端的通讯能够被加密且经过认证。

  • config/certs 目录包含三个文件分别是:

    • http.p12: 这是一个 PKCS#12 格式的文件(通常带有.p12或.pfx扩展名),包含了 Elasticsearch HTTP 层用来进行 TLS/SSL 通信所需的一切,包括一个私钥、相应的公钥证书(服务器证书)及 CA 证书链。客户端使用这个文件来验证它们正在与正确的服务器进行通信,并且此服务器也信任该客户端。
    • http_ca.crt: CA (Certificate Authority) 根证书或中间证书,用于验证通过 HTTP 协议连接至 Elasticsearch 服务端点的身份。当客户端尝试建立 HTTPS 连接时,它会检查来自 Elasticsearch 的证书是否由这个 CA 签名;这是确保双方通信安全的重要步骤之一。
    • transport.p12: 同样为 PKCS#12 格式,但这个特定的文件是给 Elasticsearch 节点之间内部传输层使用的。在集群内,节点间需
      要相互认证,transport.p12就包含着让不同 Elasticsearch 实例能互相识别所需的私钥和证书。
  • 总之,http.p12服务于面向 Web 的接口,而transport.p12则处理 Elasticsearch 群集内的交互;两者都依赖于http_ca.crt来进行身份验证过程的一部分。

ES证书过期的影响

  • ‌集群无法增加新节点‌:特别是在重启集群时,节点无法加入集群,导致无法正常重启。‌

  • ‌访问异常‌:如果使用证书连接ES集群,会导致无法正常访问集群。

  • ‌安全风险‌:证书过期会破坏证书链的信任,可能引发安全漏洞。

  • ‌日志干扰‌:会持续出现证书过期的错误日志,干扰问题排查和诊断。

查看证书的过期时间

  • 通过openssl查看证书的过期时间

1
2
3
4
5
6
7
8
9
10
# 查看crt证书到期时间
# -dates: 显示证书的开始时间和结束时间
# -noout: 不输出证书的详细信息
openssl x509 -in config/certs/http_ca.crt -dates -noout

# 查看p12证书到期时间
# -clcerts: 只显示证书,不显示私钥
# -nokeys: 不输出私钥
# -password pass: 指定私钥的密码,这里为空(因为在创建证书时没有设置密码),注意密码必须写在pass:的后面,不加这个参数会提示你输入密码,直接回车即可
openssl pkcs12 -in ca.p12 -password pass: -clcerts -nokeys | openssl x509 -dates -noout
  • 通过ES的API查看证书过期时间

1
curl -XGET -k -u 'elastic:123456' 'https://127.0.0.1:9200/_ssl/certificates?pretty'

证书过期处理

  • Elasticsearch 8 的证书创建需要使用命令行工具 elasticsearch-certutil,这部分的详细信息可以参考官方文档:elasticsearch-certutil

  • 当证书过期时,需要重新生成证书,并更新config/certs目录下的文件,更新前要备份原证书。

备份原证书

1
2
$ cp -r config/certs config/certs.bak
$ rm -rf config/certs/*

生成新证书

生成CA证书

  • 生成crt证书

1
2
3
4
5
6
7
# --days 36500: 指定证书的有效期,单位为天,这里设置为 36500 天,大约 10 年
$ bin/elasticsearch-certutil ca --pem --out new-ca.zip --days 36500
# 解压
$ unzip new-ca.zip
# 将创建的证书移动到指定目录
$ mv ca/ca.crt config/certs/http_ca.crt
$ mv ca/ca.key config/certs/http_ca.key
  • 也可以生成PKCS#12格式的证书

1
$ bin/elasticsearch-certutil ca --out config/certs/ca.p12 --days 36500

生成transport证书

1
2
3
4
5
# 基于crt证书
$ bin/elasticsearch-certutil cert --ca-cert config/certs/http_ca.crt --ca-key config/certs/http_ca.key --out config/certs/transport.p12 --days 36500

# 基于PKCS#12格式的证书
$ bin/elasticsearch-certutil cert --ca config/certs/ca.p12 --out config/certs/transport.p12 --days 36500

生成http证书

1
2
# 这里是交互式命令行
$ bin/elasticsearch-certutil http
  • 输出说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Generate a CSR? [y/N]n # 不生成CSR
Use an existing CA? [y/N]y # 使用已有的CA

# 以下区分crt证书和PKCS#12格式的证书
# crt 证书
CA Path: certs/http_ca.crt # CA证书,这里相对路径是相对应 config 目录,也可以是绝对路径
CA Key: certs/http_ca.key # CA密钥,这里相对路径是相对应 config 目录,也可以是绝对路径

# PKCS#12格式的证书
CA Path: certs/ca.p12 # CA证书,这里相对路径是相对应 config 目录,也可以是绝对路径
Password for ca.p12: # CA密码,因为没有设置密码,所以这里直接回车

For how long should your certificate be valid? [5y] 100y # 证书有效期,单位为年,默认是 5 年,这里设置为 100 年
Generate a certificate per node? [y/N]n # 不为每个节点创建独立的证书,即所有节点都使用同一个证书
Enter all the hostnames that you need, one per line.
When you are done, press <ENTER> once more to move on to the next step.

localhost # 主机名,这里可以添加多个,回车一行一个,这里应该填写集群内所有节点服务器的hostname,可以通过 hostname 命令查看
ip-10-250-0-17.cn-northwest-1.compute.internal
ip-10-250-0-173.cn-northwest-1.compute.internal
ip-10-250-0-239.cn-northwest-1.compute.internal

You entered the following hostnames.

- localhost
- ip-10-250-0-17.cn-northwest-1.compute.internal
- ip-10-250-0-173.cn-northwest-1.compute.internal
- ip-10-250-0-239.cn-northwest-1.compute.internal

Is this correct [Y/n]y # 确认主机名是否正确

Enter all the IP addresses that you need, one per line.
When you are done, press <ENTER> once more to move on to the next step.

127.0.0.1 # 主机IP,这里可以添加多个,回车一行一个,这里应该填写集群内所有节点服务器的IP地址
10.250.0.17
10.250.0.173
10.250.0.239

You entered the following IP addresses.

- 127.0.0.1
- 10.250.0.17
- 10.250.0.173
- 10.250.0.239

Is this correct [Y/n]y # 确认IP是否正确

Do you wish to change any of these options? [y/N]n # 不修改任何选项

If you wish to use a blank password, simply press <enter> at the prompt below.
Provide a password for the "http.p12" file: [<ENTER> for none] # 直接回车不设置密码

What filename should be used for the output zip file? [/usr/local/elasticsearch/elasticsearch-8.17.3/elasticsearch-ssl-http.zip] # 输出文件名,这里可以自定义,默认是 elasticsearch-ssl-http.zip

Zip file written to /usr/local/elasticsearch/elasticsearch-8.17.3/elasticsearch-ssl-http.zip
  • 解压并将http证书拷贝到config/certs目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
$ unzip elasticsearch-ssl-http.zip
Archive: elasticsearch-ssl-http.zip
creating: elasticsearch/
inflating: elasticsearch/README.txt # 说明文件
inflating: elasticsearch/http.p12 # http证书
inflating: elasticsearch/sample-elasticsearch.yml # 示例elasticsearch配置文件
creating: kibana/
inflating: kibana/README.txt # 说明文件
inflating: kibana/elasticsearch-ca.pem # kibana用于验证ES的证书,即 elasticsearch.ssl.certificateAuthorities 中的配置
inflating: kibana/sample-kibana.yml # 示例kibana配置文件

# 将http证书拷贝到config/certs目录下
$ cp elasticsearch/http.p12 config/certs/http.p12

分发到ES集群中的每个节点

  • 上面创建新的证书时我们只在一个节点上进行即可,之后将生成好的证书分发到ES集群中的其它节点,这里就是 http.p12transport.p12,将其拷贝到每个节点的 config/certs 目录下,拷贝前做好原证书的备份。

  • 如有必要也可以拷贝 ca.p12 或者 http_ca.crthttp_ca.key 到每个节点的 config/certs 目录下

重启ES服务

  • 集群中的节点依次重启

1
$ bin/elasticsearch -d
  • 重启时可能会报错

1
2
org.elasticsearch.ElasticsearchSecurityException: failed to load SSL configuration [xpack.security.transport.ssl] - cannot read configured [PKCS12] keystore (as a truststore) [/usr/local/elasticsearch/elasticsearch-8.17.3/config/certs/transport.p12] - this is usually caused by an incorrect password; (a keystore password was provided)
# 虽然我们没有给transport.p12设置密码,但这里依旧提示提供的密码不正确,实际上这里使用的是 secure_password
  • 解决方法

1
2
3
4
5
6
7
8
9
10
# 使用bin/elasticsearch-keystore list查看现有的密钥列表
$ bin/elasticsearch-keystore list
keystore.seed
xpack.security.http.ssl.keystore.secure_password
xpack.security.transport.ssl.keystore.secure_password
xpack.security.transport.ssl.truststore.secure_password
# 删除secure_password后再次重启ES服务就会正常了
$ bin/elasticsearch-keystore remove xpack.security.http.ssl.keystore.secure_password
$ bin/elasticsearch-keystore remove xpack.security.transport.ssl.keystore.secure_password
$ bin/elasticsearch-keystore remove xpack.security.transport.ssl.truststore.secure_password

替换Kibana的证书

  • 将上面创建好的 kibana/elasticsearch-ca.pem 拷贝到Kibana服务器,比如 /usr/local/kibana/kibana-8.17.3/config/certs/elasticsearch-ca.pem

  • 修改Kibana配置文件 config/kibana.yml 中的 elasticsearch.ssl.certificateAuthorities 配置,使其指向 /usr/local/kibana/kibana-8.17.3/config/certs/elasticsearch-ca.pem

1
elasticsearch.ssl.certificateAuthorities: ["/usr/local/kibana/kibana-8.17.3/config/certs/elasticsearch-ca.pem"]
  • 重启Kibana服务

证书格式转换

1
2
3
4
5
6
7
8
# p12转换为crt格式
$ openssl pkcs12 -in config/certs/ca.p12 -out config/certs/http_ca.crt -nokeys
# p12转换为key格式
$ openssl pkcs12 -in config/certs/ca.p12 -out config/certs/http_ca.key -nocerts -nodes
# p12转换为pem格式
$ openssl pkcs12 -in config/certs/ca.p12 -out config/certs/http_ca.pem -nodes
# crt转换回PKCS12格式
$ openssl pkcs12 -export -out config/certs/http_ca.p12 -inkey config/certs/http_ca.key -in config/certs/http_ca.crt -name "My CA"

生成http证书时为每个节点单独配置证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Generate a certificate per node? [y/N]y # 是否为每个节点单独配置证书,这里选择是
node #1 name: node-1 # 节点名称,必须与ES配置文件中的node.name一致

Enter all the hostnames that you need, one per line. # 输入 node-1 节点的hostname
When you are done, press <ENTER> once more to move on to the next step.

localhost # 习惯加上 localhost
ip-10-250-0-239.cn-northwest-1.compute.internal # node-1 的 hostname

You entered the following hostnames.

- localhost
- ip-10-250-0-239.cn-northwest-1.compute.internal

Is this correct [Y/n]y # 确认是否正确

Enter all the IP addresses that you need, one per line. # 输入 node-1 节点的IP地址
When you are done, press <ENTER> once more to move on to the next step.

127.0.0.1 # 习惯加上 127.0.0.1
10.250.0.239 # node-1 的 IP

You entered the following IP addresses.

- 127.0.0.1
- 10.250.0.239

Is this correct [Y/n]y # 确认是否正确

Do you wish to change any of these options? [y/N]n # 不修改任何选项
Generate additional certificates? [Y/n]y # 是否生成其他证书,这里选择是,接着为其它节点创建证书
node #2 name: node-2 # 节点名称,必须与ES配置文件中的node.name一致
# 依次为每个节点创建证书
………………

Generate additional certificates? [Y/n]n # 创建好所有节点的证书后,选择n,不再创建新的证书

If you wish to use a blank password, simply press <enter> at the prompt below.
Provide a password for the "http.p12" file: [<ENTER> for none] # 直接回车不设置密码

What filename should be used for the output zip file? [/usr/local/elasticsearch/elasticsearch-8.17.3/elasticsearch-ssl-http.zip] # 输出文件名,这里可以自定义,默认是 elasticsearch-ssl-http.zip

Zip file written to /usr/local/elasticsearch/elasticsearch-8.17.3/elasticsearch-ssl-http.zip
  • 此时解压查看文件结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unzip elasticsearch-ssl-http.zip
Archive: elasticsearch-ssl-http.zip
creating: elasticsearch/
creating: elasticsearch/node-1/
inflating: elasticsearch/node-1/README.txt
inflating: elasticsearch/node-1/http.p12 # node-1 的证书
inflating: elasticsearch/node-1/sample-elasticsearch.yml
creating: elasticsearch/node-2/
inflating: elasticsearch/node-2/README.txt
inflating: elasticsearch/node-2/http.p12 # node-2 的证书
inflating: elasticsearch/node-2/sample-elasticsearch.yml
creating: elasticsearch/node-3/
inflating: elasticsearch/node-3/README.txt
inflating: elasticsearch/node-3/http.p12 # node-3 的证书
inflating: elasticsearch/node-3/sample-elasticsearch.yml
creating: kibana/
inflating: kibana/README.txt
inflating: kibana/elasticsearch-ca.pem # kibana 的证书
inflating: kibana/sample-kibana.yml
  • 将对应的证书拷贝到对应节点的 config/certs 目录下