当前位置:   article > 正文

ElasticSearch 8.x 使用 High Level Client 以 HTTPS 方式链接,SSL 证书、主机名验证器 各是什么,如何忽略_connection is closed at org.elasticsearch.client.r

connection is closed at org.elasticsearch.client.restclient.extractandwrapc

ElasticSearch

1、ElasticSearch学习随笔之基础介绍
2、ElasticSearch学习随笔之简单操作
3、ElasticSearch学习随笔之java api 操作
4、ElasticSearch学习随笔之SpringBoot Starter 操作
5、ElasticSearch学习随笔之嵌套操作
6、ElasticSearch学习随笔之分词算法
7、ElasticSearch学习随笔之高级检索
8、ELK技术栈介绍
9、Logstash部署与使用
10、ElasticSearch 7.x 版本使用 BulkProcessor 实现批量添加数据
11、ElasticSearch 8.x 弃用了 High Level REST Client,移除了 Java Transport Client,推荐使用 Elasticsearch Java API
12、ElasticSearch 8.x 使用 snapshot(快照)进行数据迁移
13、ElasticSearch 8.x 版本如何使用 SearchRequestBuilder 检索
14、ElasticSearch 8.x 使用 High Level Client 以 HTTPS 方式链接,SSL 证书、主机名验证器 各是什么,如何忽略
15、ElasticSearch 8.x 创建父子文档,用Join类型字段以及用has_child、has_parent 检索
16、ElasticSearch如何提高写入效率【面试题,面道既学到】

ElasticSearch,创始人 Shay Banon(谢巴农)
本文主要讲解ElasticSearch 高级搜索实战,来满足复杂的业务场景,还是用 Kibana 来操作



前言

在平时测试环境中,我们可以通过 IP 地址 或者 域名【http://***】来简单粗暴的连接 ElasticSearch 服务,比较内网测试没必要考虑别的,连接上能进行索引的操作即可;不过到了生产环境,安全问题成了 头号杀手,毕竟数据无价嚒,不过目前很多企业应用都会部署到云端,应用ElasticSearch 服务之前其实也是属于内网连接,并不会暴漏链接到外面,再加上云服务自身的安全和防火前的保护,所以安全基本上不用考虑了。
可以公司是有规范的,无论是 DB 数据库还是缓存,还是像 ElasticSearch 这种搜索引擎必须要有 用户名和密码 这层安全校验的,这是安全最基本的,所以应对不同的环境 或许 就需要不同的连接方式了。

一:pom 依赖

对于 ElasticSearch 客户端的版本,不需要太高,稳定很重要,对于有些莫名其妙的问题,换一个 版本的 客户端有可能就好了,亲身经历

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.15.2</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

二:开放式连接方式

public static RestHighLevelClient getClient(){
    RestClientBuilder builder = RestClient.builder(
            new HttpHost(HOSTNAME, 9200, "http")
    );
    RestHighLevelClient client = new RestHighLevelClient(builder);
    return client;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三:用户名密码验证方式

这种方式在其他博客中已经提到好几次了,放到这里只为有需要的 码友 们拷贝代码。

private static RestHighLevelClient createClient(){
    String hostname = "192.168.0.67";
    int port = 9200;
    String esUsername = "your es username";
    String esPassword = "your es password";
    final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUsername, esPassword));
    RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(hostname, port))
            .setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
    return new RestHighLevelClient(restClientBuilder);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

四:忽略 SSL证书 和 主机名验证

生产环境的 ElasticSearch 有时可能是通过域名来访问的,并且是 https 开头的,那就需要 SSL/TLS 认证了,但是我们并不需要,那只能忽略了。

4.1 忽略 SSL 认证

按上面说的,ElasticSearch 访问地址是 https://***,而只配置了 用户名密码,那用客户端链接则 可能 会报如下错误:

javax.net.ssl.SSLHandshakeException:PKIX path building failed:sun.security.provider.certpath.SunCertPathBuilderException:unable to find valid certification path to requested target
at org.elasticsearch.client.RestClient.extractAndWrapCause(RestClient.java:783)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:218)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:205)
at org.elasticsearch.client.RestHighLevelclient.internalPerformRequest(RestHighLevelclient.java:1454)
at org.elasticsearch.client.RestHighLevelclient.performRequest(RestHighLevelclient.java:1424)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

此时我们需要忽略 SSL 认证,然忽略 SSL 的写法也有好几种。

注意: 以下三种方式选择其中一种就可以,那种适合就用那种。

方式一

首先获取 TLS 的 SSLContext 实例,再进行初始化,初始化的时候什么都不做。

public static RestHighLevelClient createClient(){
    String hostname = "es.test.com";
    int port = 9200;
    String esUsername = "your es username";
    String esPassword = "your es password";
    // 配置用户名和密码
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUsername, esPassword));
    RestClientBuilder clientBuilder = RestClient.builder(new HttpHost(hostname, port, "https"));
    clientBuilder.setHttpClientConfigCallback( httpAsyncClientBuilder -> {
                // 配置认证支持
                httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                // 忽略证书配置
                try {
                    SSLContext sslContext = SSLContext.getInstance("TLS");
                    sslContext.init(null, new TrustManager[] {
                                    new X509TrustManager() {
                                        @Override
                                        public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
                                                throws CertificateException {
                                            // 忽略证书错误 信任任何客户端证书
                                        }

                                        @Override
                                        public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
                                                throws CertificateException {
                                            // 忽略证书错误 信任任何客户端证书
                                        }

                                        @Override
                                        public X509Certificate[] getAcceptedIssuers() {
                                            return new X509Certificate[0];
                                        }
                                    }
                            },
                            null);
                    httpAsyncClientBuilder.setSSLContext(sslContext);
                } catch (NoSuchAlgorithmException | KeyManagementException e) {
                    System.out.println("忽略证书错误");
                }
                // 忽略 hostname 校验认证
                httpAsyncClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
                return httpAsyncClientBuilder;
            });
    return new RestHighLevelClient(clientBuilder);
}
  • 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

方式二

首先创建一个信任策略的 TrustStrategy,再通过策略构建一个 SSLContext 。

public static RestHighLevelClient createClient(){
    String hostname = "es.test.com";
    int port = 9200;
    String esUsername = "your es username";
    String esPassword = "your es password";
    // 配置用户名和密码
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUsername, esPassword));
    RestClientBuilder clientBuilder = RestClient.builder(new HttpHost(hostname, port, "https"));
    clientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
        httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        try {
            // 创建一个信任所有证书的 TrustStrategy 策略
            TrustStrategy acceptTrustStrategy = (chain, authType) -> true;
            // 使用 SSLContextBuilder 创建 SSLContext
            SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(null, acceptTrustStrategy).build();
            httpAsyncClientBuilder.setSSLContext(sslContext);
        } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            e.printStackTrace();
        }
        return httpAsyncClientBuilder;
    });
    return new RestHighLevelClient(clientBuilder);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

方式三

这里需要一个引入一个第三方的 jar 包,封装了我们需要的 SSL 认证实例。

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart</artifactId>
    <version>8.1.4</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

下面通过第三方 jar 包提供的 SSLFactory 来得到 SSLContext 。

public static RestHighLevelClient createClient(){
    String hostname = "es.test.com";
    int port = 9200;
    String esUsername = "your es username";
    String esPassword = "your es password";
    // 用户名和密码认证
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUsername, esPassword));
    // 配置策略工厂
    SSLFactory sslFactory = SSLFactory.builder()
            .withUnsafeTrustMaterial()
            .withUnsafeHostnameVerifier()
            .build();
    RestClientBuilder clientBuilder = RestClient.builder(new HttpHost(hostname, port, "https"));
    clientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
        httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        // 通过策略工厂获取一个 SSLContext
        httpAsyncClientBuilder.setSSLContext(sslFactory.getSslContext());
        return httpAsyncClientBuilder;
    });
    return new RestHighLevelClient(clientBuilder);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

4.2 忽略 主机名验证

处理 SSL 认证,还有可能包如下错误:

java.io.IOException: Host name 'devintes.jibo.cn' does not match the certificate subject provided by the peer (CN=elasticsearch-devint-master)
  • 1

我们接着忽略,只需要在忽略 SSL 是再忽略 主机名验证就可以了,代码如下:

httpAsyncClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
  • 1

其实再上面的 方式三 中,用 SSLFactory 也是可以忽略的。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号