Elasticsearch SSL 证书更新

1.前提条件

  1. 当前配置是基于 Elasticsearch 8.6.2 在 RPM 安装的前提下对证书进行更新的操作步骤,具体安装请参考:Elasticsearch 8.6.2 集群安装
  2. 通常 TCP 证书不会过期,不需要考虑更新的问题,只需要更新 HTTP 证书即可。

2.配置过程

证书分为 TCP 和 HTTP 两类,默认在之前的配置文件中都有体现,例如:

# HTTP 证书
xpack.security.http.ssl:
  enabled: true
  keystore.path: certs/http.p12

# TCP 证书
xpack.security.transport.ssl:
  enabled: true
  verification_mode: certificate
  keystore.path: certs/transport.p12
  truststore.path: certs/transport.p12

其中 TCP 证书又包括两个分别是 keystore 和 truststore 主要是对应的别名部分不同,正常我们用同一个文件即可,也就是说一个文件里面包含多个 key,既包括 keystore 也包括 truststore。

在配置之前我们首先生成 CA,然后基于该 CA 再创建 TCP 证书和 HTTP 证书,虽然这里是同一个 CA,但是要注意两套证书并不会相互影响,完全可以单独生成并使用。

我们首先生成 CA,在其中一个节点执行就可以,步骤如下:

# 选择 1 个节点执行 如果下面没有强调我们的工作目录都是 /opt/elasticsearch-ca
mkdir /opt/elasticsearch-ca
cd /opt/elasticsearch-ca
# 生成 CA
elasticsearch-certutil ca --pem

执行后默认会在 Elasticsearch 的安装目录下生成 elastic-stack-ca.zip 文件,我们这里使用 RPM 方式安装生成的位置就是 /usr/share/elasticsearch 下面:

mv /usr/share/elasticsearch/elastic-stack-ca.zip .
unzip elastic-stack-ca.zip
chown -R elasticsearch:elasticsearch ca

解压后会出现 ca 目录,下面分别有 ca.crtca.key 两个文件,其中 ca.key 是私钥,ca.crt 是被私钥签名过的证书,证书的默认有效期是 3 年,我们可以使用 openssl 命令查看:

openssl x509 -in ca/ca.crt -noout -dates

需要将上面证书的内容发送到 Elasticsearch 集群中所有的节点,后续要用到,分发完然后即可开始配置更新 Elasticsearch 的证书。

2.1.生成 TCP 层证书

绝大部分情况下 TCP 证书不需要更新,当前章节仅给出详细可执行的步骤,以备万一,因此如果 Elasticsearch 集群原有证书正常,当前章节可直接跳过,只根据需要更新 HTTP 证书即可。

首先要查看当前证书的密码,每个节点密码都不同:

elasticsearch-keystore list

image-20230418161101576

下面 3 个分别表示 HTTP 证书、TCP keystore、TCP truststore 这 3 类证书的密码,默认情况下后两个 TCP 证书是指向同一个文件,所以密码是相同的,查看密码可以执行:

elasticsearch-keystore show xpack.security.transport.ssl.keystore.secure_password

每个机器查看密码都采用相同的命令,具体 TCP 证书的位置是:/etc/elasticsearch/certs/transport.p12,可以查看其中的内容:

/usr/share/elasticsearch/jdk/bin/keytool -keystore /etc/elasticsearch/certs/transport.p12 -list

这里使用了 Elasticsearch 内置 JDK 的 keytool 工具,也可以使用系统默认 JDK 的 keytool 命令,执行后输入上面查询到的密码,可以看到具体的指纹,目前是 3 项,分别对应 keystore 和 truststore 的。

为了方便滚动升级,我们在每个节点上将新生成的 CA 内容添加到目前存在的证书中:

# 注意每个节点都需要执行
/usr/share/elasticsearch/jdk/bin/keytool -importcert -trustcacerts -noprompt -keystore /etc/elasticsearch/certs/transport.p12 -storepass <password> -alias transport-new-ca -file ca/ca.crt

执行后可以再次查看内容:

/usr/share/elasticsearch/jdk/bin/keytool -keystore /etc/elasticsearch/certs/transport.p12 -list

这样是保证切换证书时,节点可以被信任。

然后开始为每个节点生成新的证书:

# 每个节点都执行生成新的证书
elasticsearch-certutil cert --ca-cert /opt/elasticsearch-ca/ca/ca.crt --ca-key /opt/elasticsearch-ca/ca/ca.key

最后注意输入密码,为了简单方便管理每个节点生成相同的密码即可,证书默认会生成到 /usr/share/elasticsearch/elastic-certificates.p12 ,然后我们需要放到证书目录下:

# 所有节点都需要操作
chown elasticsearch:elasticsearch /usr/share/elasticsearch/elastic-certificates.p12
mv /usr/share/elasticsearch/elastic-certificates.p12 /etc/elasticsearch/certs

然后我们开始执行滚动重启,在每个节点上轮流执行下面的步骤:

首先修改配置文件指向新的证书:

xpack.security.transport.ssl:
  enabled: true
  verification_mode: certificate
  # 只修改这里一项配置即可
  keystore.path: certs/elastic-certificates.p12
  # 这一项务必保持原样
  truststore.path: certs/transport.p12

修改完成之后保存配置,然后将最新设置的密码添加到密码库中,否则 Elasticsearch 将无法解密证书:

elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password

添加完成后,重启 Elasticsearch 服务:

systemctl restart elasticsearch.service

重启成功后,就使用新的证书运行了,然后对其他节点都按照上面操作配置就完成了证书替换。

替换后可以将原有证书 transport.p12 的旧条目删除掉,例如:

keytool -delete -noprompt -alias <alias name>  -keystore /etc/elasticsearch/certs/transport.p12 -storepass <password>

但是其实不建议这么做,因为 truststore 的密码仍然每个节点都不一样,所以之后可能会容易混淆,所以我们需要开启第二轮的滚动配置,使 truststore 也指向我们新的 elastic-certificates.p12,首先在所有节点将刚才添加到 transport.p12 的 CA 再添加一次:

# 所有节点都要执行
/usr/share/elasticsearch/jdk/bin/keytool -importcert -trustcacerts -noprompt -keystore /etc/elasticsearch/certs/elastic-certificates.p12 -storepass <password> -alias trust-ca -file ca/ca.crt

执行后 elastic-certificates.p12 中就包含了我们的 truststore 的签名,这个时候只需要每个机器修改配置然后滚动重启:

修改配置文件如下:

xpack.security.transport.ssl:
  enabled: true
  verification_mode: certificate
  keystore.path: certs/elastic-certificates.p12
  # 修改为新的 p12 证书路径
  truststore.path: certs/elastic-certificates.p12

修改后需要将我们新的密码设置进去:

elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password

完成之后需要重启 Elasticsearch 服务:

systemctl restart elasticsearch.service

每个节点都依次执行一遍,所有证书就都更换完毕了,另外 transport.p12 这个证书已经没用了,直接删除掉就行了。

最后也可以访问页面或者使用 curl 查看最新的证书情况:

curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://ecs16:9200/_ssl/certificates?pretty"

2.2.生成 HTTP 证书

生成 HTTP 证书同样需要利用最前面生成的 CA,每个节点都需要依次执行并滚动重启,首先执行如下命令:

# 每个机器都需要单独生成
elasticsearch-certutil http

执行之后是交互式的命令:

询问是否生成 CSR?输入 N 并且确认

询问是否使用已存在的 CA?输入 Y 并且确认

然后输入 CA 的路径,当前是 /opt/elasticsearch-ca/ca/ca.crt

然后输入私钥的路径,当前是 /opt/elasticsearch-ca/ca/ca.key

image-20230418165636860

然后继续询问证书的过期时间,默认是 5 年,根据需要输入即可

然后询问是否根据节点自动创建,这里输入 N 并确认。

image-20230418165822373

然后继续询问输入当前节点的 DNS 名称,这个一定输入实际的主机名,否则将无法用主机名访问:

image-20230418170009256

然后询问输入访问节点的 IP,输入当前 Elasticsearch 监听的 IP,并确认:

image-20230418175417007

最后询问是否更改配置只需要输入 N 确认,最后输入密码,可以和 TCP 证书的保持一致,最后确认会询问输出目录:

image-20230418175547387

默认是在 /usr/share/elasticsearch/elasticsearch-ssl-http.zip,我们移动到当前目录并解压:

mv /usr/share/elasticsearch/elasticsearch-ssl-http.zip /opt/elasticsearch-ca
unzip elasticsearch-ssl-http.zip

解压后会生成 elasticsearch 目录和 kibana 目录,其中 elasticsearch 目录中就是生成的 HTTP 证书,然后我们修改权限并替换原有的 HTTP 证书文件:

# 修改权限
chown elasticsearch:elasticsearch elasticsearch/http.p12
# 替换证书
mv elasticsearch/http.p12 /etc/elasticsearch/certs
# 替换公钥证书
cp ca/ca.crt /etc/elasticsearch/certs/http_ca.crt

替换后 Elasticsearch 会自动加载,但是由于密码问题目前会报错,因此需要执行命令覆盖之前的密码:

elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password

由于配置文件中的 HTTP 证书名称和当前生成的名称一样所以不需要修改配置文件,重启 Elasticsearch 服务即可:

systemctl restart elasticsearch.service

然后每个节点都按照上面的步骤操作一遍就完成了证书的更新,注意每个节点要正确设置主机和 IP 地址,然后可以访问验证 Elasticsearch API 查看证书情况:

curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://ecs16:9200/_ssl/certificates?pretty"

这样就完成了集群 HTTP 证书的更新。

Reference:

  1. https://www.elastic.co/guide/en/elasticsearch/reference/8.6/update-node-certs-different.html