给Elasticsearch集群做安全配置这件事,远比想象中麻烦。很多人以为在elasticsearch.yml里加几行TLS/SSL配置就能收工,结果往往是节点之间互相不认证书、Kibana连不上、客户端报handshake failed,最后只能回滚。我这次把一套三节点ES集群从裸HTTP切换到全链路TLS加密,顺便把密钥库管理的坑也踩了个遍。这篇就是第07篇,针对Elasticsearch集群安全配置中最核心的TLS/SSL与密钥库管理,把原理、实操和排障完整捋一遍。1. 为什么非做集群安全不可1.1 裸奔的HTTP和Transport端口,等于把数据写在明信片上Elasticsearch安装完成后默认是“零安全”状态,HTTP端口9200直接以明文对外服务,节点之间的Transport端口9300也是明文通信。很多初学者觉得“内网环境不用加密”,但现实往往是:一旦有运维同事误开放了端口,或者内网被攻破一台机器,攻击者就能直接用HTTP请求把索引里的数据全部拉走,连密码都不需要。更重要的是节点间通信。ES节点之间要同步分片、选举主节点,这些数据通过9300端口传递。如果这个链路明文裸露,抓包工具可以直接看到索引内容、文档内容,甚至能伪造一个节点加入集群。这种风险用“明信片”来类比再合适不过:你往信封里塞了重要资料,结果邮局一路上都是透明玻璃,谁路过都能瞄一眼。TLS/SSL要解决的,就是把明信片换成加密邮件。1.2 安全配置=三件事:传输加密、节点可信、客户端可信真正把ES集群做安全,不只是加个证书那么简单。拆开看,需要解决三个独立问题:传输加密:HTTP层和Transport层的数据包必须加密,防止被抓包后直接读明文。节点可信:新节点加入集群时,必须证明“我是自己人”,而不是随便一个伪装进程连上9300端口就能混进来。客户端可信:Kibana、Java程序、脚本调用ES时,既要验证ES服务端证书是否可信,也需要决定是否要求客户端出示自己的证书。这三个问题对应的技术方案就是TLS/SSL协议和PKI证书体系。HTTP层的TLS保护REST API,Transport层的TLS保护节点间通信,而证书体系解决“谁可信”的问题。1.3 基础版安全能力边界不同发行版和版本在安全功能上差异不小。这里说的是常用场景:官方发行版的基础安全功能,在6.8之后已经支持TLS加密、内置用户认证、基于角色的访问控制等,并不需要额外购买商业插件。7.x、8.x的配置方式有细微差别,8.x默认开启安全,7.x默认关闭,所以如果你还在维护7.x集群,这一篇的配置方法仍然很通用。需要提醒的是:开启安全后,内置的elastic超级用户默认没有密码,必须通过初始化脚本设置。这一步很多人会漏,结果集群看似起来了,实际上所有请求都被401拒绝。2. 证书体系与密钥库管理的核心概念2.1 CA、证书链和“信任”这件事HTTPS的信任模型用一个生活化例子理解最方便:你去一家公司办事,前台不认识你,但你掏出身份证件,身份证上有公安局的印章,前台认这个印章,于是认你。这里的“公安局”就是CA(证书颁发机构),身份证就是证书,身份证上的印章就是CA的数字签名。自建ES集群时,我们不需要找外面的公共CA买证书,完全可以自己做“公安局”,也就是自建CA。用这个CA给每个节点签发身份证(节点证书),然后让所有节点都信任这个CA。只要证书是由同一个CA签发的,节点之间就天然互相认可。这也是为什么我强烈建议自建CA而不是直接生成自签名证书:自签名证书相当于你自己给自己盖了个章,别的节点不认识;而统一CA签发的证书,所有节点都认同一套信任链。2.2 PKCS12、JKS、PEM三者的选择和证书打交道时,你一定会碰到三种文件格式,别被它们绕晕:格式后缀内容典型工具适用场景PEM.crt / .key / .pemBase64文本证书或私钥OpenSSLNginx、Kibana等大量中间件PKCS12.p12 / .pfx二进制容器,可同时装证书和私钥keytool、certutilJava体系、ES最推荐JKS.jksJava专用密钥库keytool老版本Java应用Elasticsearch官方最推荐PKCS12,原因很直接:它可以把私钥、证书、信任的CA都放进一个文件里,用密码保护,配置路径也简单。PEM的好处是肉眼可读、方便调试,但在ES里要分别配置证书路径、私钥路径、CA路径,稍有遗漏就会握手失败。2.3 Keystore和Truststore到底谁管谁密钥库这个概念经常把新手搞糊涂。简单记住两句话:Keystore(密钥库):存放“我自己的身份证明”,包括私钥和配套证书。对外通信时,我用它证明我是谁。Truststore(信任库):存放“我信任的CA证书”,用于验证对方出示的证书是否合法。用一个场景串起来:A节点连接B节点时,A把自己的证书从Keystore里取出来发给B;B收到后,拿着Truststore里的CA证书去验证A的证书签名,验过了才建立加密通道。所以每个节点既要有Keystore证明自己,也要有Truststore验证别人。在ES里,如果你使用单个PKCS12文件,这个文件可以同时扮演Keystore和Truststore角色,既存放自己的私钥证书,也存放CA证书,配置时通常把同一个路径写在两处,或者只写Keystore路径并让ES复用其中包含的CA。PEM模式下则必须分别指定三个路径。3. 动手签发证书:使用内置certutil搭建企业级CA3.1 集群规划:节点、域名、IP怎么定假设现在有一套三节点集群,规划如下:节点名IP域名角色node1192.168.1.11es-node1.internal.examplemaster + datanode2192.168.1.12es-node2.internal.examplemaster + datanode3192.168.1.13es-node3.internal.examplemaster + data证书里的IP和域名不是随便写的。TLS握手时,客户端(或另一个节点)会检查访问地址是否和证书里的“使用者备用名称”匹配,也就是SAN(Subject Alternative Name)。如果你的证书只写了域名,却用IP访问,握手会直接失败。所以我建议:只要IP会被直接访问,就必须把IP写进证书SAN;如果Kibana会通过域名访问,也要把域名写进去。3.2 创建自建CA在node1上执行官方自带的证书工具:cd /usr/share/elasticsearch bin/elasticsearch-certutil ca --pem --out ca.zip执行后输入CA密码,这里建议设置一个强密码并妥善保存。命令会在当前目录生成ca.zip,解压后得到ca/ca.crt和ca/ca.key,前者是CA根证书,后者是CA私钥。也有很多人图省事会直接跳过CA文件,但我的习惯是把CA单独保存到安全目录,后续签发新节点证书、轮换证书都能复用。没有这套CA,以后想加节点,要么全部重新签发,要么就得再建一套信任体系,非常痛苦。3.3 为每个节点签发证书拿到CA后,为三个节点分别签发证书。以node1为例:bin/elasticsearch-certutil cert --pem \ --ca-cert ca/ca.crt \ --ca-key ca/ca.key \ --ca-pass "你的CA密码" \ --name node1 \ --dns es-node1.internal.example,localhost \ --ip 192.168.1.11,127.0.0.1 \ --out node1.zipnode2、node3把--name、--dns、--ip换成对应值即可。解压后,每个zip里包含node1.crt和node1.key,分别是对应节点的证书和私钥。这里有两个容易踩的小坑。第一个是--dns里必须带localhost、--ip里带127.0.0.1,否则本机使用curl https://localhost:9200做自检时也会报主机名不匹配。第二个是CA私钥如果设置了密码,--ca-pass必须正确,否则签不出来证书。3.4 密钥库分发与权限检查如果你更习惯PKCS12方式,可以用certutil直接生成p12文件,一个文件里同时包含证书、私钥和CA:bin/elasticsearch-certutil cert \ --ca-cert ca/ca.crt \ --ca-key ca/ca.key \ --ca-pass "你的CA密码" \ --dns es-node1.internal.example,es-node2.internal.example,es-node3.internal.example,localhost \ --ip 192.168.1.11,192.168.1.12,192.168.1.13,127.0.0.1 \ --out elastic-certificates.p12这种方式生成的p12在所有节点上可以用同一个文件,因为它包含所有节点的SAN。不过生产环境我仍建议每节点独立证书,这样某台机器私钥泄露时,只用吊销那一台,不至于整个集群信任体系崩掉。证书文件复制到每个节点的config/certs目录后,马上做两个检查:chown -R elasticsearch:elasticsearch /usr/share/elasticsearch/config/certs chmod 600 /usr/share/elasticsearch/config/certs/*私钥和p12文件权限必须锁死,否则ES启动时会因为“权限过于开放”直接拒绝加载密钥库。4. 配置TLS:三节点集群加密落地4.1 elasticsearch.yml中的Transport层TLS配置把node1的config/elasticsearch.yml打开,在末尾追加一段。使用PEM证书方式的Transport配置如下:xpack.security.enabled: true xpack.security.transport.ssl.enabled: true xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.certificate: certs/node1.crt xpack.security.transport.ssl.key: certs/node1.key xpack.security.transport.ssl.certificate_authorities: certs/ca/ca.crt注意路径是相对于config目录的。verification_mode我建议先写成certificate,它表示只验证证书是否由受信CA签发,不做主机名严格匹配。写成full意味着还要校验对方证书里的域名/IP与访问地址一致,在节点间通信时非常容易因为DNS解析问题翻车。如果是p12方式,配置是这样:xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12 xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p124.2 HTTP层TLS配置HTTP层负责对外提供REST API,这一步必须有,否则你从客户端访问还是明文。继续追加:xpack.security.http.ssl.enabled: true xpack.security.http.ssl.certificate: certs/node1.crt xpack.security.http.ssl.key: certs/node1.key xpack.security.http.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.http.ssl.client_authentication: noneclient_authentication先保持none,表示服务端只出示证书,不强制要求客户端出示证书。等Kibana、Java客户端都跑通了,再按需求升级成双向认证,否则一开始就开双向认证,排错难度会翻倍。三个节点都要把上面配置写上,只是证书路径换成各自的节点证书。4.3 密钥库密码的安全存储如果你用了p12文件,ES默认会要求你提供密钥库密码。这个密码不能直接写进elasticsearch.yml,因为它是明文文件,权限再严也有泄露风险。ES提供了专门的secure settings机制:cd /usr/share/elasticsearch bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password执行后会交互式输入密码,密码被加密存储在config/elasticsearch.keystore中。PEM模式如果想给私钥单独设置密码,对应设置项是xpack.security.transport.ssl.secure_key_passphrase。这一步很容易漏。我见过有人配置好了所有路径,ES启动时仍然报keystore password was incorrect,原因就是忘了把密码写进elasticsearch-keystore。4.4 初始化密码与启动集群所有节点配置完成后,按顺序逐台启动。全部起来后,执行内置密码初始化:bin/elasticsearch-setup-passwords auto这个脚本会连接集群,为elastic、kibana_system等内置用户生成随机密码,在终端打印出来。建议立刻保存。如果你希望密码可控,可以用:bin/elasticsearch-setup-passwords interactive此时用curl验证HTTP层加密是否生效:curl -u elastic:你的密码 \ --cacert /usr/share/elasticsearch/config/certs/ca/ca.crt \ https://192.168.1.11:9200正常会返回集群信息。如果去掉--cacert,一定会报证书验证失败,这恰恰说明TLS已经生效。5. 客户端接入TLS:curl、Kibana、Java5.1 三种客户端信任姿势TLS加密只是第一步,客户端要访问ES,还必须“信任”集群的证书。不同客户端有不同做法:curl:用--cacert指定CA证书。Kibana:在kibana.yml里配置elasticsearch.ssl.certificateAuthorities。Java程序:在SSLContext里加载Truststore。以Kibana为例,kibana.yml核心配置如下:server.host: "0.0.0.0" server.ssl.enabled: true server.ssl.certificate: "/etc/kibana/certs/kibana.crt" server.ssl.key: "/etc/kibana/certs/kibana.key" elasticsearch.hosts: ["https://es-node1.internal.example:9200"] elasticsearch.ssl.certificateAuthorities: ["/etc/kibana/certs/ca/ca.crt"]这里Kibana自身也开启了SSL,浏览器访问Kibana时用的就是Kibana的证书。如果浏览器不想装CA证书,可以暂时跳过验证,但生产环境一定要把CA导入受信列表。5.2 单向认证与双向认证怎么选默认client_authentication: none是单向认证,客户端验证服务端证书,服务端不验证客户端。这种模式适合Web应用、数据分析工具,配置简单,绝大多数场景够用。如果你们安全规范要求“只有持证客户端才能访问ES”,就把HTTP层改成双向:xpack.security.http.ssl.client_authentication: required改成required之后,curl命令也必须带上客户端证书和私钥:curl -u elastic:密码 \ --cacert /path/ca.crt \ --cert /path/client.crt \ --key /path/client.key \ https://192.168.1.11:9200Kibana也要配客户端证书,否则连不上ES。我的建议是:如果只是内部工具使用,单向足够;如果ES直接暴露给第三方系统,双向更稳,而且一定要配合用户认证一起用。5.3 Java客户端里的SSLContext配置Java里的ES客户端最常用RestClient,通过Apache HttpClient发送请求。连接HTTPS集群时,需要手动构建SSLContext:KeyStore trustStore = KeyStore.getInstance("PKCS12"); try (InputStream in = new FileInputStream("/path/truststore.p12")) { trustStore.load(in, "密码".toCharArray()); } SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(trustStore, null) .build(); RestClient client = RestClient.builder( new HttpHost("es-node1.internal.example", 9200, "https")) .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setSSLContext(sslContext)) .build();这里最关键的是Truststore里必须包含ES集群的CA证书。很多Java程序启动时报PKIX path building failed,十有八九就是没有正确加载Truststore。Hostname验证方面,如果证书SAN里有对应域名,不需要额外关闭验证;如果一定要用IP访问但证书里没有IP,那才需要自己写HostnameVerifier,不推荐为了省事直接NoopHostnameVerifier。6. 常见问题、坑位与排查实录6.1 节点之间互相不认,握手失败最典型的报错是javax.net.ssl.SSLHandshakeException,日志里能看到PKIX path building failed或者No trusted certificate found。原因基本是节点证书不是由同一CA签发,或者certificate_authorities路径写错。排查思路很简单:在所有节点上分别执行openssl verify,用CA证书验证节点证书:openssl verify -CAfile /usr/share/elasticsearch/config/certs/ca/ca.crt \ /usr/share/elasticsearch/config/certs/node1.crt如果验证失败,说明证书签发关系有问题,需要重新用同一CA签一份。如果验证通过,就去检查各节点certificate_authorities是否都指向同一个ca.crt。6.2 验证模式坑:verification_mode到底是certificate还是full我在排障时遇到过这样一个案例:A节点和B节点连接时,A一直报peer not authenticated,但证书明明是好的。最后发现是verification_mode设成了full,而A访问B时用的地址是IP 192.168.1.12,B的证书里也写了这个IP,按理说应该能通过。问题出在ES的Transport模式是双向连接,节点名解析和连接地址可能不一致,导致主机名校验失败。我的经验是:在节点间Transport层,certificate模式已经足够安全,它确保对方证书受信且私钥匹配,只是不校验主机名。把full留给对公网的HTTPS场景更合理。6.3 启动时找不到证书或权限损坏ES启动失败,日志提示Private key is encrypted but no key passphrase is configured或Permission denied,这类问题多半不在证书本身,而在文件路径和权限。检查项如下:配置文件里的路径是否相对于config目录写对。证书目录的属主是否为启动ES的系统用户。私钥或p12文件权限是否为600。路径末尾是否误写了空格。另外,配置文件路径里不要用/etc/elasticsearch之类的绝对路径,除非你确认目录属主和权限没问题。保持默认的config/certs相对路径最省心。6.4 忘记密码、证书过期、滚动替换密码遗忘这种事,真发生了也别慌。如果只是密钥库密码丢了,可以重新生成elasticsearch.keystore,再执行elasticsearch-keystore add重新输入。如果elastic用户密码忘了,在任意节点执行elasticsearch-setup-passwords interactive重新设置一遍即可,但要注意这个操作会覆盖所有内置用户密码。证书过期是另一个高频问题。生产集群证书到期前一个月,最好做一次滚动替换。流程是:用原有CA重新签发新节点证书,把新文件放到对应位置,逐台重启节点。因为CA没变,其他节点的Truststore不用改,替换成本很低。这再次印证了自建CA的价值:只要CA私钥还在,换节点证书是几分钟的事。6.5 问题排查速查表现象可能原因处理方式握手失败:PKIX path building failed客户端Truststore缺少CA用--cacert或把CA加入Truststore握手失败:hostname in certificate didn't match访问地址不在证书SAN中用证书里的域名访问,或重签证书加IP节点无法加入集群各节点Truststore不一致统一所有节点使用同一CA及证书启动报keystore password was incorrect密钥库密码未写进elasticsearch-keystore执行elasticsearch-keystore add设置密码日志提示Permission denied证书文件或目录权限不对设置属主为es用户,权限600访问9200被拒绝安全已开启但未初始化密码执行elasticsearch-setup-passwords auto证书过期未做到期维护用原有CA重签并逐节点滚动重启最后分享一个我在实际运维中养成的习惯:每次配置集群安全前,先把整套步骤在本地一台临时节点上跑一遍,确认证书路径、密码、验证模式都没问题,再批量同步到生产节点。TLS配置的报错信息有时很绕,但只要掌握“CA统一、路径正确、权限严密、密码进keystore”这四条主线,大多数问题都能快速定位。ES集群安全没有想象中那么高不可攀,认真做一次,后面就是长期稳定运行。
给Elasticsearch集群做安全配置这件事,远比想象中麻烦。很多人以为在elasticsearch.yml里加几行TLS/SSL配置就能收工,结果往往是节点之间互相不认证书、Kibana连不上、客户端报handshake failed,最后只能回滚。我这次把一套三节点ES集群从裸HTTP切换到全链路TLS加密,顺便把密钥库管理的坑也踩了个遍。这篇就是第07篇,针对Elasticsearch集群安全配置中最核心的TLS/SSL与密钥库管理,把原理、实操和排障完整捋一遍。1. 为什么非做集群安全不可1.1 裸奔的HTTP和Transport端口,等于把数据写在明信片上Elasticsearch安装完成后默认是“零安全”状态,HTTP端口9200直接以明文对外服务,节点之间的Transport端口9300也是明文通信。很多初学者觉得“内网环境不用加密”,但现实往往是:一旦有运维同事误开放了端口,或者内网被攻破一台机器,攻击者就能直接用HTTP请求把索引里的数据全部拉走,连密码都不需要。更重要的是节点间通信。ES节点之间要同步分片、选举主节点,这些数据通过9300端口传递。如果这个链路明文裸露,抓包工具可以直接看到索引内容、文档内容,甚至能伪造一个节点加入集群。这种风险用“明信片”来类比再合适不过:你往信封里塞了重要资料,结果邮局一路上都是透明玻璃,谁路过都能瞄一眼。TLS/SSL要解决的,就是把明信片换成加密邮件。1.2 安全配置=三件事:传输加密、节点可信、客户端可信真正把ES集群做安全,不只是加个证书那么简单。拆开看,需要解决三个独立问题:传输加密:HTTP层和Transport层的数据包必须加密,防止被抓包后直接读明文。节点可信:新节点加入集群时,必须证明“我是自己人”,而不是随便一个伪装进程连上9300端口就能混进来。客户端可信:Kibana、Java程序、脚本调用ES时,既要验证ES服务端证书是否可信,也需要决定是否要求客户端出示自己的证书。这三个问题对应的技术方案就是TLS/SSL协议和PKI证书体系。HTTP层的TLS保护REST API,Transport层的TLS保护节点间通信,而证书体系解决“谁可信”的问题。1.3 基础版安全能力边界不同发行版和版本在安全功能上差异不小。这里说的是常用场景:官方发行版的基础安全功能,在6.8之后已经支持TLS加密、内置用户认证、基于角色的访问控制等,并不需要额外购买商业插件。7.x、8.x的配置方式有细微差别,8.x默认开启安全,7.x默认关闭,所以如果你还在维护7.x集群,这一篇的配置方法仍然很通用。需要提醒的是:开启安全后,内置的elastic超级用户默认没有密码,必须通过初始化脚本设置。这一步很多人会漏,结果集群看似起来了,实际上所有请求都被401拒绝。2. 证书体系与密钥库管理的核心概念2.1 CA、证书链和“信任”这件事HTTPS的信任模型用一个生活化例子理解最方便:你去一家公司办事,前台不认识你,但你掏出身份证件,身份证上有公安局的印章,前台认这个印章,于是认你。这里的“公安局”就是CA(证书颁发机构),身份证就是证书,身份证上的印章就是CA的数字签名。自建ES集群时,我们不需要找外面的公共CA买证书,完全可以自己做“公安局”,也就是自建CA。用这个CA给每个节点签发身份证(节点证书),然后让所有节点都信任这个CA。只要证书是由同一个CA签发的,节点之间就天然互相认可。这也是为什么我强烈建议自建CA而不是直接生成自签名证书:自签名证书相当于你自己给自己盖了个章,别的节点不认识;而统一CA签发的证书,所有节点都认同一套信任链。2.2 PKCS12、JKS、PEM三者的选择和证书打交道时,你一定会碰到三种文件格式,别被它们绕晕:格式后缀内容典型工具适用场景PEM.crt / .key / .pemBase64文本证书或私钥OpenSSLNginx、Kibana等大量中间件PKCS12.p12 / .pfx二进制容器,可同时装证书和私钥keytool、certutilJava体系、ES最推荐JKS.jksJava专用密钥库keytool老版本Java应用Elasticsearch官方最推荐PKCS12,原因很直接:它可以把私钥、证书、信任的CA都放进一个文件里,用密码保护,配置路径也简单。PEM的好处是肉眼可读、方便调试,但在ES里要分别配置证书路径、私钥路径、CA路径,稍有遗漏就会握手失败。2.3 Keystore和Truststore到底谁管谁密钥库这个概念经常把新手搞糊涂。简单记住两句话:Keystore(密钥库):存放“我自己的身份证明”,包括私钥和配套证书。对外通信时,我用它证明我是谁。Truststore(信任库):存放“我信任的CA证书”,用于验证对方出示的证书是否合法。用一个场景串起来:A节点连接B节点时,A把自己的证书从Keystore里取出来发给B;B收到后,拿着Truststore里的CA证书去验证A的证书签名,验过了才建立加密通道。所以每个节点既要有Keystore证明自己,也要有Truststore验证别人。在ES里,如果你使用单个PKCS12文件,这个文件可以同时扮演Keystore和Truststore角色,既存放自己的私钥证书,也存放CA证书,配置时通常把同一个路径写在两处,或者只写Keystore路径并让ES复用其中包含的CA。PEM模式下则必须分别指定三个路径。3. 动手签发证书:使用内置certutil搭建企业级CA3.1 集群规划:节点、域名、IP怎么定假设现在有一套三节点集群,规划如下:节点名IP域名角色node1192.168.1.11es-node1.internal.examplemaster + datanode2192.168.1.12es-node2.internal.examplemaster + datanode3192.168.1.13es-node3.internal.examplemaster + data证书里的IP和域名不是随便写的。TLS握手时,客户端(或另一个节点)会检查访问地址是否和证书里的“使用者备用名称”匹配,也就是SAN(Subject Alternative Name)。如果你的证书只写了域名,却用IP访问,握手会直接失败。所以我建议:只要IP会被直接访问,就必须把IP写进证书SAN;如果Kibana会通过域名访问,也要把域名写进去。3.2 创建自建CA在node1上执行官方自带的证书工具:cd /usr/share/elasticsearch bin/elasticsearch-certutil ca --pem --out ca.zip执行后输入CA密码,这里建议设置一个强密码并妥善保存。命令会在当前目录生成ca.zip,解压后得到ca/ca.crt和ca/ca.key,前者是CA根证书,后者是CA私钥。也有很多人图省事会直接跳过CA文件,但我的习惯是把CA单独保存到安全目录,后续签发新节点证书、轮换证书都能复用。没有这套CA,以后想加节点,要么全部重新签发,要么就得再建一套信任体系,非常痛苦。3.3 为每个节点签发证书拿到CA后,为三个节点分别签发证书。以node1为例:bin/elasticsearch-certutil cert --pem \ --ca-cert ca/ca.crt \ --ca-key ca/ca.key \ --ca-pass "你的CA密码" \ --name node1 \ --dns es-node1.internal.example,localhost \ --ip 192.168.1.11,127.0.0.1 \ --out node1.zipnode2、node3把--name、--dns、--ip换成对应值即可。解压后,每个zip里包含node1.crt和node1.key,分别是对应节点的证书和私钥。这里有两个容易踩的小坑。第一个是--dns里必须带localhost、--ip里带127.0.0.1,否则本机使用curl https://localhost:9200做自检时也会报主机名不匹配。第二个是CA私钥如果设置了密码,--ca-pass必须正确,否则签不出来证书。3.4 密钥库分发与权限检查如果你更习惯PKCS12方式,可以用certutil直接生成p12文件,一个文件里同时包含证书、私钥和CA:bin/elasticsearch-certutil cert \ --ca-cert ca/ca.crt \ --ca-key ca/ca.key \ --ca-pass "你的CA密码" \ --dns es-node1.internal.example,es-node2.internal.example,es-node3.internal.example,localhost \ --ip 192.168.1.11,192.168.1.12,192.168.1.13,127.0.0.1 \ --out elastic-certificates.p12这种方式生成的p12在所有节点上可以用同一个文件,因为它包含所有节点的SAN。不过生产环境我仍建议每节点独立证书,这样某台机器私钥泄露时,只用吊销那一台,不至于整个集群信任体系崩掉。证书文件复制到每个节点的config/certs目录后,马上做两个检查:chown -R elasticsearch:elasticsearch /usr/share/elasticsearch/config/certs chmod 600 /usr/share/elasticsearch/config/certs/*私钥和p12文件权限必须锁死,否则ES启动时会因为“权限过于开放”直接拒绝加载密钥库。4. 配置TLS:三节点集群加密落地4.1 elasticsearch.yml中的Transport层TLS配置把node1的config/elasticsearch.yml打开,在末尾追加一段。使用PEM证书方式的Transport配置如下:xpack.security.enabled: true xpack.security.transport.ssl.enabled: true xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.certificate: certs/node1.crt xpack.security.transport.ssl.key: certs/node1.key xpack.security.transport.ssl.certificate_authorities: certs/ca/ca.crt注意路径是相对于config目录的。verification_mode我建议先写成certificate,它表示只验证证书是否由受信CA签发,不做主机名严格匹配。写成full意味着还要校验对方证书里的域名/IP与访问地址一致,在节点间通信时非常容易因为DNS解析问题翻车。如果是p12方式,配置是这样:xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12 xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p124.2 HTTP层TLS配置HTTP层负责对外提供REST API,这一步必须有,否则你从客户端访问还是明文。继续追加:xpack.security.http.ssl.enabled: true xpack.security.http.ssl.certificate: certs/node1.crt xpack.security.http.ssl.key: certs/node1.key xpack.security.http.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.http.ssl.client_authentication: noneclient_authentication先保持none,表示服务端只出示证书,不强制要求客户端出示证书。等Kibana、Java客户端都跑通了,再按需求升级成双向认证,否则一开始就开双向认证,排错难度会翻倍。三个节点都要把上面配置写上,只是证书路径换成各自的节点证书。4.3 密钥库密码的安全存储如果你用了p12文件,ES默认会要求你提供密钥库密码。这个密码不能直接写进elasticsearch.yml,因为它是明文文件,权限再严也有泄露风险。ES提供了专门的secure settings机制:cd /usr/share/elasticsearch bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password执行后会交互式输入密码,密码被加密存储在config/elasticsearch.keystore中。PEM模式如果想给私钥单独设置密码,对应设置项是xpack.security.transport.ssl.secure_key_passphrase。这一步很容易漏。我见过有人配置好了所有路径,ES启动时仍然报keystore password was incorrect,原因就是忘了把密码写进elasticsearch-keystore。4.4 初始化密码与启动集群所有节点配置完成后,按顺序逐台启动。全部起来后,执行内置密码初始化:bin/elasticsearch-setup-passwords auto这个脚本会连接集群,为elastic、kibana_system等内置用户生成随机密码,在终端打印出来。建议立刻保存。如果你希望密码可控,可以用:bin/elasticsearch-setup-passwords interactive此时用curl验证HTTP层加密是否生效:curl -u elastic:你的密码 \ --cacert /usr/share/elasticsearch/config/certs/ca/ca.crt \ https://192.168.1.11:9200正常会返回集群信息。如果去掉--cacert,一定会报证书验证失败,这恰恰说明TLS已经生效。5. 客户端接入TLS:curl、Kibana、Java5.1 三种客户端信任姿势TLS加密只是第一步,客户端要访问ES,还必须“信任”集群的证书。不同客户端有不同做法:curl:用--cacert指定CA证书。Kibana:在kibana.yml里配置elasticsearch.ssl.certificateAuthorities。Java程序:在SSLContext里加载Truststore。以Kibana为例,kibana.yml核心配置如下:server.host: "0.0.0.0" server.ssl.enabled: true server.ssl.certificate: "/etc/kibana/certs/kibana.crt" server.ssl.key: "/etc/kibana/certs/kibana.key" elasticsearch.hosts: ["https://es-node1.internal.example:9200"] elasticsearch.ssl.certificateAuthorities: ["/etc/kibana/certs/ca/ca.crt"]这里Kibana自身也开启了SSL,浏览器访问Kibana时用的就是Kibana的证书。如果浏览器不想装CA证书,可以暂时跳过验证,但生产环境一定要把CA导入受信列表。5.2 单向认证与双向认证怎么选默认client_authentication: none是单向认证,客户端验证服务端证书,服务端不验证客户端。这种模式适合Web应用、数据分析工具,配置简单,绝大多数场景够用。如果你们安全规范要求“只有持证客户端才能访问ES”,就把HTTP层改成双向:xpack.security.http.ssl.client_authentication: required改成required之后,curl命令也必须带上客户端证书和私钥:curl -u elastic:密码 \ --cacert /path/ca.crt \ --cert /path/client.crt \ --key /path/client.key \ https://192.168.1.11:9200Kibana也要配客户端证书,否则连不上ES。我的建议是:如果只是内部工具使用,单向足够;如果ES直接暴露给第三方系统,双向更稳,而且一定要配合用户认证一起用。5.3 Java客户端里的SSLContext配置Java里的ES客户端最常用RestClient,通过Apache HttpClient发送请求。连接HTTPS集群时,需要手动构建SSLContext:KeyStore trustStore = KeyStore.getInstance("PKCS12"); try (InputStream in = new FileInputStream("/path/truststore.p12")) { trustStore.load(in, "密码".toCharArray()); } SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(trustStore, null) .build(); RestClient client = RestClient.builder( new HttpHost("es-node1.internal.example", 9200, "https")) .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setSSLContext(sslContext)) .build();这里最关键的是Truststore里必须包含ES集群的CA证书。很多Java程序启动时报PKIX path building failed,十有八九就是没有正确加载Truststore。Hostname验证方面,如果证书SAN里有对应域名,不需要额外关闭验证;如果一定要用IP访问但证书里没有IP,那才需要自己写HostnameVerifier,不推荐为了省事直接NoopHostnameVerifier。6. 常见问题、坑位与排查实录6.1 节点之间互相不认,握手失败最典型的报错是javax.net.ssl.SSLHandshakeException,日志里能看到PKIX path building failed或者No trusted certificate found。原因基本是节点证书不是由同一CA签发,或者certificate_authorities路径写错。排查思路很简单:在所有节点上分别执行openssl verify,用CA证书验证节点证书:openssl verify -CAfile /usr/share/elasticsearch/config/certs/ca/ca.crt \ /usr/share/elasticsearch/config/certs/node1.crt如果验证失败,说明证书签发关系有问题,需要重新用同一CA签一份。如果验证通过,就去检查各节点certificate_authorities是否都指向同一个ca.crt。6.2 验证模式坑:verification_mode到底是certificate还是full我在排障时遇到过这样一个案例:A节点和B节点连接时,A一直报peer not authenticated,但证书明明是好的。最后发现是verification_mode设成了full,而A访问B时用的地址是IP 192.168.1.12,B的证书里也写了这个IP,按理说应该能通过。问题出在ES的Transport模式是双向连接,节点名解析和连接地址可能不一致,导致主机名校验失败。我的经验是:在节点间Transport层,certificate模式已经足够安全,它确保对方证书受信且私钥匹配,只是不校验主机名。把full留给对公网的HTTPS场景更合理。6.3 启动时找不到证书或权限损坏ES启动失败,日志提示Private key is encrypted but no key passphrase is configured或Permission denied,这类问题多半不在证书本身,而在文件路径和权限。检查项如下:配置文件里的路径是否相对于config目录写对。证书目录的属主是否为启动ES的系统用户。私钥或p12文件权限是否为600。路径末尾是否误写了空格。另外,配置文件路径里不要用/etc/elasticsearch之类的绝对路径,除非你确认目录属主和权限没问题。保持默认的config/certs相对路径最省心。6.4 忘记密码、证书过期、滚动替换密码遗忘这种事,真发生了也别慌。如果只是密钥库密码丢了,可以重新生成elasticsearch.keystore,再执行elasticsearch-keystore add重新输入。如果elastic用户密码忘了,在任意节点执行elasticsearch-setup-passwords interactive重新设置一遍即可,但要注意这个操作会覆盖所有内置用户密码。证书过期是另一个高频问题。生产集群证书到期前一个月,最好做一次滚动替换。流程是:用原有CA重新签发新节点证书,把新文件放到对应位置,逐台重启节点。因为CA没变,其他节点的Truststore不用改,替换成本很低。这再次印证了自建CA的价值:只要CA私钥还在,换节点证书是几分钟的事。6.5 问题排查速查表现象可能原因处理方式握手失败:PKIX path building failed客户端Truststore缺少CA用--cacert或把CA加入Truststore握手失败:hostname in certificate didn't match访问地址不在证书SAN中用证书里的域名访问,或重签证书加IP节点无法加入集群各节点Truststore不一致统一所有节点使用同一CA及证书启动报keystore password was incorrect密钥库密码未写进elasticsearch-keystore执行elasticsearch-keystore add设置密码日志提示Permission denied证书文件或目录权限不对设置属主为es用户,权限600访问9200被拒绝安全已开启但未初始化密码执行elasticsearch-setup-passwords auto证书过期未做到期维护用原有CA重签并逐节点滚动重启最后分享一个我在实际运维中养成的习惯:每次配置集群安全前,先把整套步骤在本地一台临时节点上跑一遍,确认证书路径、密码、验证模式都没问题,再批量同步到生产节点。TLS配置的报错信息有时很绕,但只要掌握“CA统一、路径正确、权限严密、密码进keystore”这四条主线,大多数问题都能快速定位。ES集群安全没有想象中那么高不可攀,认真做一次,后面就是长期稳定运行。