Elasticsearch如何优雅的激活X-Pack这个终极守护神

975 阅读10分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

说起x-pack这个组件,不是什么新鲜的功能,其实在elasticsearch早期版本就已经有了,而且x-pack在功能对于elasticsearch的安全性来说也毋庸置疑,但是俗话说得好,一分钱难倒英雄汉,更何况花销的单位可能是数万甚至更多,所以早期在中国并没有被大规模普及,能用的要么是财大气粗的金融、银行以及运营商等重量级客户;要么是通过“其他渠道”偷偷使用的中小客户。

“菜谱哥”可能注意到完全收费对于x-pack的发展起到了很大的制约,而且收入可能也没有预期那么理想,所以从elasticsearch 6.3版本以后,x-pack开始逐步开放免费功能。一石激起千层浪,凭借elasticsearch多年打下来的江山,x-pack的应用如雨后春笋般的席卷了elasticsearch圈,尤其是需要将elasticsearch的访问暴露在公网或者公有云的业务场景下。

在此种场景下,作为elasticsearch重度用户的笔者的公司在做项目时,接触到用户的elasticsearch集群也五花八门,所以很多场景下,就会遇到连接了开启了x-pack的elasticsearch,所以本文的着眼点就是简单地讲解下x-pack设置elasticsearch访问保护以及相关的客户端代码适配的功能,其余的功能笔者也在学习,后续如果有成果的话,会及时分享

正文

进入正题,下面将从elasticsearch的服务端配置以及transport-client客户端的适配两个方面来讲解下适配的过程,最后再讲解下kibana相关的适配:

elasticsearch的服务端配置

生成证书

此处需要说明下,当前遇见过两种三类配置,可能还有其他的,这说明x-pack的认证还是很灵活的,但是带来的影响就是适配成本较高,尤其是刚接触一个自己不熟悉的客户的x-pack认证方式时候,如果这个认证方式还是小众的情况下,那就太酸爽了...

证书的类型分为PKCS#12格式(.p12)以及PEM格式(.crt或者.pem),生成方式如下:

PKCS#12

进入elasticsearch的安装目录,执行下面的命令

bin/elasticsearch-certutil cert -out config/elastic-certificates.p12 -pass ""

执行之后查看文件生成结果,进入config目录查看:

找到对应的文件 ,生成成功。

如果要指定client端登录的具体信息,限制client不能随意连接elasticsearch,则可以通过生成一个yaml文件,并在生成p12文件时作为输入即可:

[root@node1 cert_blog]# vi config/instance.yml
将实例信息添加到 yml 文件
instances:
  - name: 'node1'
    dns: [ 'node1.elastic.test.com' ]
  - name: "node2"
    dns: [ 'node2.elastic.test.com' ]
  - name: 'my-kibana'
    dns: [ 'kibana.local' ]
  - name: 'logstash'
    dns: [ 'logstash.local' ]

生成证书的命令变为:

bin/elasticsearch-certutil cert -in config/instance.yml -out config/elastic-certificates.p12 -pass ""

本文暂时未限制client相关的信息,所以后续也会在此基础上进行适配,至此 PKCS#12格式的验证文件生成完毕。

PEM

pem方式比较特殊,可以使用elasticsearch自带工具生成的crt文件进行校验,也可以使用openssl生成的pem文件进行校验,前一种方式使用的较多,后一种使用的相对较少。笔者遇到的客户现场就是后一种方式,网上资料很少,在填了无数坑之后才搞定的...

  • 使用elasticsearch-certutil生成crt文件

执行下面的命令:

bin/elasticsearch-certutil ca --pem

结果如下:

命令执行之后会生成一个zip文件,需要手动指定zip文件的存放地址,我指定的是:/home/elastic/elastic-stack-ca.zip

解压该文件,得到ca文件夹,文件夹中有两个文件:

这两个文件就是基础的认证文件,再使用这两个文件生成需要的验证文件:

./elasticsearch-6.8.0/bin/elasticsearch-certutil cert --ca-cert ca/ca.crt --ca-key ca/ca.key --pem --name client --out client.zip 结果如下:

找到client.zip解压,得到两个文件:

至此,服务端需要的验证文件生成完毕

  • 使用openssl生成pem文件

首先检查openssl是否安装,rpm -qa | grep openssl,如果有结果输出则证明已经安装了openssl,如果未安装先安装openssl

按照下面的顺序执行命令:

# Root CA
openssl genrsa -out root-ca-key.pem 2048
openssl req -new -x509 -sha256 -key root-ca-key.pem -out root-ca.pem
# Admin cert
openssl genrsa -out admin-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem
openssl req -new -key admin-key.pem -out admin.csr
openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem
# Node cert(Optional)
openssl genrsa -out node-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in node-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out node-key.pem
openssl req -new -key node-key.pem -out node.csr
openssl x509 -req -in node.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out node.pem
# Cleanup
rm admin-key-temp.pem
rm admin.csr
rm node-key-temp.pem
rm node.csr

其中Root CA是基础的验证文件,Admin cert可以理解为服务端验证文件的生成,Node cert可以理解为client端使用的验证文件,由于都是基于Root CA生成的验证文件,所以可以验证通过,从脚本可以看出,真正起作用的是xxx-key.pem以及xxx.pem这两个文件,后续服务端的配置也是基于这两个文件来进行的,详细的过程参照Generate certificates(微信公众号中无法使用超链接,我直接把链接贴进来吧:opendistro.github.io/for-elastic…

elasticsearch配置

下面进行配置,修改elasticsearch.yml文件:

  • PKCS#12 加上以下配置:
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
  • PEM crt格式验证文件

加上以下配置:

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.key: certs/client.key
xpack.security.transport.ssl.certificate: certs/client.crt
xpack.security.transport.ssl.certificate_authorities: certs/ca.crt

pem格式验证文件

加上以下配置:

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.key:  certs/admin-key.pem
xpack.security.transport.ssl.certificate: certs/admin.pem
xpack.security.transport.ssl.certificate_authorities: [ "certs/root-ca.pem" ]

然后重启elasticsearch,如果是集群的话,整个集群在配置修改完毕后需要完全重启才能生效。

重启成功后,需要设置登录密码,可以选择自动生成:

bin/elasticsearch-setup-passwords auto

也可以手动生成,建议手动生成,便于使用和管理,命令如下:

 bin/elasticsearch-setup-passwords interactive

本次配置需要设置elastic,apm_system,kibana,logstash_system,beats_system,remote_monitoring_user所有这些用户的密码,如果某些用户和功能不需要,则可以在上一步的elasticsearch.yml中配置功能禁用,界面如下:

如果要禁用功能,则在elasticsearch.yml中加入如下配置,例子如下:

xpack.security.enabled: true
xpack.monitoring.enabled: false
xpack.watcher.enabled: false
xpack.graph.enabled: false

配置完毕后,尝试访问elasticsearch

在浏览器输入:http://172.16.43.164(elasticsearch-ip):9200

如果提示输入用户名和密码,则说明配置成功.

使用elastic用户登录,显示elasticsearch集群相关的信息,流程完成。

elasticsearch客户端配置

服务端配置完毕后,剩下就是transport-client端的配置了,

将上一步生成的各种在配置文件中配置的验证文件放到client端代码能访问到的位置,本例中,为了方便使用,笔者直接将文件放到了工程目录下。

另外,elasticsearch6.X版本笔者还是使用的transport-client,7.X之后才换的rest-client,所以下文都是基于transport-client提供的例子代码。如果使用的是rest-client代码,可以引入rest-client中的x-pack client,差别应该不大,这里就不多说了。

更换transport-client的依赖为x-pack-transport,具体的依赖为:

<!-- add the x-pack jar as a dependency -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>x-pack-transport</artifactId>
            <version>6.8.0</version>
        </dependency>

此处需要注意,maven的仓库中x-pack-transport的版本只有从6.8.11版本开始的相关适配:

所以如果使用的elasticsearch的版本不在下面的列表中,就只能从elasticsearch的官网下载了,需要在工程的pom的文件中加入repository配置:

<repositories>
        <!-- add the elasticsearch repo -->
        <repository>
            <id>elasticsearch-releases</id>
            <url>https://artifacts.elastic.co/maven</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

但是elastic的官网速度相当蛋疼,下载很费劲,建议由条件的用户可以使用vpn来加速下载,实在不行就通过外部jar包依赖的方式来解决问题(这种方式比较麻烦,需要手动解决很多依赖问题,笔者试了之后发现坑太多,果断花钱选择了第一种,果然有钱人的生活就是幸福啊....)。

报的问题解决后,下一步就是代码的适配了,代码的适配简单来说就是将之前的TransportClient改成PreBuiltXPackTransportClient即可,然后修改下setting即可:

PKCS#12

String filePath =
                System.getProperty("user.dir") + File.separator + "certs" + File.separator;
        System.out.println(filePath);
        /**
         * 如果es集群安装了x-pack插件则以此种方式连接集群
         * 1. java客户端的方式是以tcp协议在9300端口上进行通信
         * 2. http客户端的方式是以http协议在9200端口上进行通信
         */
        Settings settings = Settings.builder()
                .put("xpack.security.user""userName:password")
                .put("cluster.name""bangcle_es")
                .put("client.transport.sniff"false)
                .put("xpack.security.enabled"true)
                .put("xpack.security.transport.ssl.enabled"true)
                .put("xpack.security.transport.ssl.keystore.path", filePath + "elastic-certificates.p12")//这里的文件要保证能访问到
                .put("xpack.security.transport.ssl.truststore.path", filePath + "elastic-certificates.p12")
                .put("xpack.security.transport.ssl.verification_mode""certificate")
                .build();
        TransportClient client = new PreBuiltXPackTransportClient(settings)
                .addTransportAddress(new TransportAddress(InetAddress.getByName("tidb01"), 9300));

PEM

String filePath =
                System.getProperty("user.dir") + File.separator + "certs" + File.separator;
        System.out.println(filePath);
        /**
         * 如果es集群安装了x-pack插件则以此种方式连接集群
         * 1. java客户端的方式是以tcp协议在9300端口上进行通信
         * 2. http客户端的方式是以http协议在9200端口上进行通信
         */
        Settings settings = Settings.builder()
                .put("xpack.security.user""userName:password")
                .put("cluster.name""bangcle_es")
                .put("client.transport.sniff"false)
                .put("xpack.ssl.key", filePath + "client-key.pem")
                .put("xpack.ssl.certificate", filePath + "client.pem")
                .put("xpack.ssl.certificate_authorities", filePath + "root-ca.pem")
                .put("xpack.security.transport.ssl.enabled""true")
                .put("xpack.security.transport.ssl.verification_mode""none")
                .build();
        TransportClient client = new PreBuiltXPackTransportClient(settings)
                .addTransportAddress(new TransportAddress(InetAddress.getByName("tidb01"), 9300));

这里需要说明下,笔者在使用PKCS#12方式进行验证的时候,在客户端将xpack.security.transport.ssl.verification_mode设置为certificate可以访问server端,但是使用PEM方式访问的话,ES日志中会报如下异常:

client did not trust this server's certificate, closing connection Netty4TcpChannel{localAddress=0.0.0.0/0.0.0.0:9300, remoteAddress=/172.16.19.26:55848}

后来经过查询,可以通过设置xpack.security.transport.ssl.verification_mode: none来跳过客户端的校验,最后只在服务端校验问题解决,此处仅仅是解决了问题,elasticsearch能正常操作,但未从根本上解决问题,后续有待进一步排查,初步认为可能是生成客户端的验证文件的方式可能不对,如果遇到类似问题,可以使用此方式暂时解决问题,有能根本解决问题的方式也请大家告知。

Kibana适配

最后说说kibana的适配吧,由于在kibana的配置文件中配置访问的是elasticsearch的 9200端口,所以如果仅仅配置了transport连接的验证的话,那仅需要在kibana.yml中配置elasticsearch的登录用户名和密码即可:

如果配置了http连接的验证的话,需要为kibana生成验证文件,并将验证文件配置到kibana的配置文件中,这个笔者未做验证,大概收集了下,应该有如下的配置,大家感兴趣的可以去试验下:

elasticsearch.username: "elastic"
elasticsearch.password: "xxxxxx"
server.ssl.enabled: true
server.ssl.key: certs/kibana.key
server.ssl.certificate: erts/kibana.crt
elasticsearch.ssl.certificateAuthorities: [ "certs/ca.crt" ]

这是pem的设置方式中一种,其他两种应该也类似,参照上面“elasticsearch配置”这个章节中相关的配置进行适配。

配置完成后,直接重启kibana,再次登录时,需要填写用户名和密码。

此处需要注意,默认可以使用kibana用户以及elastic用户登录kibana,由于安装了x-pack,所以两个用户的权限不同,kibana用户只能管理kibana本身相关的内容;而elasticsearch的业务数据只能通过elastic用户进行管理,理论上是可以重新分配权限的,这个感兴趣的小伙伴可以去研究下。

后记

随着大家的elasticsearch版本的升级,后续使用x-pack的场景可以预见的会越来越多,所以好好学习下还是值得的,上面的内容也是经过了各种努力和翻找才收集到并解决问题的,为了搞这个事情专门买了个VPN,终于可以上梦寐以求的google了。

其中遇到了个一个很有意思的事情,第三种也就是客户使用的那种认证方式,我在elasticsearch的官网上没有找到,最后在AWS的opendistro for elasticsearch的文档中找到了答案,不知道这种方式是不是专门给AWS或者是云用户使用的呢?

虽然过程比较煎熬,但是解决问题带来的满足感足以覆盖所有的辛苦。但是后续还要继续努力,逆水行舟不进则退,尤其对于一个已经到了劝退年龄的技术人员。so,keep passion!keep running!