早些年写过一个es的网关服务,当时觉得java对接es过于痛苦,只当是个试验性质的项目
cclient/spring-boot-es-jpa-proxy: spring-boot elasticsearch 聚合 webapi服务 (github.com)
java jvm 栈 通用的https/ssl 自签证书信任办法
见 https://github.com/lmenezes/cerebro/issues/456
现在又来踩坑了
目标是做一个分发es search和bulk请求读写的网关,兼容同一集群内的多集群
public RestHighLevelClient elasticsearchClient() {
HttpHeaders defaultHeaders = new HttpHeaders();
final ClientConfiguration clientConfiguration = ClientConfiguration
.builder()
.connectedTo("a.b.c:9200")
.usingSsl()
.withConnectTimeout(Duration.ofSeconds(5))
.withSocketTimeout(Duration.ofSeconds(3))
.withDefaultHeaders(defaultHeaders)
.withHeaders(() -> {
HttpHeaders headers = new HttpHeaders();
headers.add("currentTime", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
return headers;
})
.build();
return RestClients.create(clientConfiguration).rest();
}
未认证证书,报错
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:818)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:248)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:235)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1514)
... 1 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
看到 usingSsl() 有三个重载方法
public interface MaybeSecureClientConfigurationBuilder extends ClientConfiguration.TerminalClientConfigurationBuilder {
ClientConfiguration.TerminalClientConfigurationBuilder usingSsl();
ClientConfiguration.TerminalClientConfigurationBuilder usingSsl(SSLContext var1);
ClientConfiguration.TerminalClientConfigurationBuilder usingSsl(SSLContext var1, HostnameVerifier var2);
}
先试着重载传入SSLContext
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// final SSLContext sslContext = SSLContext.getInstance(SSL);
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
.usingSsl(sslContext)
报错 Host name 'a.b.c' does not match the certificate subject
证书和域名不匹配
java.io.IOException: Host name 'a.b.c' does not match the certificate subject provided by the peer (CN=instance)
at ..
Caused by: javax.net.ssl.SSLPeerUnverifiedException: Host name 'a.b.c' does not match the certificate subject provided by the peer (CN=instance)
再试第三个重载办法 传入HostnameVerifier 直接返回true,不验证域名和证书是否匹配,直接返回true
.usingSsl(sslContext, new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
测试成功
end