通过 SSL 使用 Elasticsearch 的 Micrometer
Micrometer with Elasticsearch over SSL
我正在尝试通过 SSL.Micrometer 与 Elasticsearch 一起使用。
我使用 1.8.0 版的 Micrometer,7.16.3 版的 Elasticsearch 和 OpenJDK 11.0.2。
因为我知道无法使用内置配置 (link) 我尝试注入自定义 HttpUrlConnectionSender 如下 class SecureHttpSender:
public class SecureHttpSender extends HttpUrlConnectionSender {
...
public SecureHttpSender(ElasticProperties properties, SecureElasticProperties secureElasticProperties) {
super(properties.getConnectTimeout(), properties.getReadTimeout());
this.secureElasticProperties = secureElasticProperties;
this.sslSocketFactory = buildSslSocketFactory();
}
@Override
public Response send(Request request) throws IOException {
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) request.getUrl().openConnection();
// if the connection is an instance of the HttpsURLConnection class, the ssl configuration will always been applied.
if (httpURLConnection instanceof HttpsURLConnection) {
// - hostname verifier
if (!secureElasticProperties.isVerifyHostname()) {
logger.debug("setting the hostname verifier to: {}", NoopHostnameVerifier.INSTANCE);
((HttpsURLConnection) httpURLConnection).setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
}
// - trust store configuration
((HttpsURLConnection) httpURLConnection).setSSLSocketFactory(sslSocketFactory);
}
return super.send(request);
} finally {
try {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception ignore) {
}
}
}
private SSLSocketFactory buildSslSocketFactory() {
SSLSocketFactory sslSocketFactory;
try (InputStream is = getInputStream(secureElasticProperties.getTrustStorePath())) {
KeyStore truststore = KeyStore.getInstance(secureElasticProperties.getTrustStoreType());
truststore.load(is, secureElasticProperties.getTrustStorePassword().toCharArray());
SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
final SSLContext sslContext = sslBuilder.build();
sslSocketFactory = sslContext.getSocketFactory();
} catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
String message = String.format("error while loading the security configuration from: %s", secureElasticProperties);
logger.error(message, e);
throw new RuntimeException("management.metrics.export.elastic.ssl");
}
return sslSocketFactory;
}
private InputStream getInputStream(String trustStorePathString) throws IOException {
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource resource = pathMatchingResourcePatternResolver.getResource(trustStorePathString);
return resource.getInputStream();
}
}
我注入了 Spring 引导,因此我可以应用所需的配置,但我收到以下错误:
ERROR 10912 --- [trics-publisher] i.m.elastic.ElasticMeterRegistry : failed to send metrics to elastic
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
服务器证书和客户端信任库有效,因为我已经成功使用了它们。
我也尝试在握手阶段强制使用特定版本的TLS协议:TLSv1.3和TLSv1.2,但仍然出现错误。
有人对如何修复它有任何建议吗?谢谢
检查 super.send
做了什么,它创建了一个新连接而不使用您创建的连接。我不建议使用 self-signed 证书和自定义信任库,但您可以设置默认 HostnameVerifier
使用
HttpsURLConnection.setDefaultHostnameVerifier
.
由于这是静态的,它将适用于所有 HttpsURLConnection
个实例,因此您无需向 Micrometer 中注入任何东西。
正确的解决方案是使用非 self-signed 证书或适当的信任库(例如:通过 javax.net.ssl.trustStore
)。
我做了一个测试,对我发布的代码进行了简单的更改,然后我解决了它:
我复制了 super.send() 方法的所有代码,添加了额外的代码来设置自定义 SslSocketFactory 并且一切正常!
所以原因是
it creates a new connection without using the one you created
正如 Jonatan 所说...这是我的一个小错误。 :)
我正在尝试通过 SSL.Micrometer 与 Elasticsearch 一起使用。
我使用 1.8.0 版的 Micrometer,7.16.3 版的 Elasticsearch 和 OpenJDK 11.0.2。
因为我知道无法使用内置配置 (link) 我尝试注入自定义 HttpUrlConnectionSender 如下 class SecureHttpSender:
public class SecureHttpSender extends HttpUrlConnectionSender {
...
public SecureHttpSender(ElasticProperties properties, SecureElasticProperties secureElasticProperties) {
super(properties.getConnectTimeout(), properties.getReadTimeout());
this.secureElasticProperties = secureElasticProperties;
this.sslSocketFactory = buildSslSocketFactory();
}
@Override
public Response send(Request request) throws IOException {
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) request.getUrl().openConnection();
// if the connection is an instance of the HttpsURLConnection class, the ssl configuration will always been applied.
if (httpURLConnection instanceof HttpsURLConnection) {
// - hostname verifier
if (!secureElasticProperties.isVerifyHostname()) {
logger.debug("setting the hostname verifier to: {}", NoopHostnameVerifier.INSTANCE);
((HttpsURLConnection) httpURLConnection).setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
}
// - trust store configuration
((HttpsURLConnection) httpURLConnection).setSSLSocketFactory(sslSocketFactory);
}
return super.send(request);
} finally {
try {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception ignore) {
}
}
}
private SSLSocketFactory buildSslSocketFactory() {
SSLSocketFactory sslSocketFactory;
try (InputStream is = getInputStream(secureElasticProperties.getTrustStorePath())) {
KeyStore truststore = KeyStore.getInstance(secureElasticProperties.getTrustStoreType());
truststore.load(is, secureElasticProperties.getTrustStorePassword().toCharArray());
SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
final SSLContext sslContext = sslBuilder.build();
sslSocketFactory = sslContext.getSocketFactory();
} catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
String message = String.format("error while loading the security configuration from: %s", secureElasticProperties);
logger.error(message, e);
throw new RuntimeException("management.metrics.export.elastic.ssl");
}
return sslSocketFactory;
}
private InputStream getInputStream(String trustStorePathString) throws IOException {
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource resource = pathMatchingResourcePatternResolver.getResource(trustStorePathString);
return resource.getInputStream();
}
}
我注入了 Spring 引导,因此我可以应用所需的配置,但我收到以下错误:
ERROR 10912 --- [trics-publisher] i.m.elastic.ElasticMeterRegistry : failed to send metrics to elastic
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
服务器证书和客户端信任库有效,因为我已经成功使用了它们。 我也尝试在握手阶段强制使用特定版本的TLS协议:TLSv1.3和TLSv1.2,但仍然出现错误。
有人对如何修复它有任何建议吗?谢谢
检查 super.send
做了什么,它创建了一个新连接而不使用您创建的连接。我不建议使用 self-signed 证书和自定义信任库,但您可以设置默认 HostnameVerifier
使用
HttpsURLConnection.setDefaultHostnameVerifier
.
由于这是静态的,它将适用于所有 HttpsURLConnection
个实例,因此您无需向 Micrometer 中注入任何东西。
正确的解决方案是使用非 self-signed 证书或适当的信任库(例如:通过 javax.net.ssl.trustStore
)。
我做了一个测试,对我发布的代码进行了简单的更改,然后我解决了它: 我复制了 super.send() 方法的所有代码,添加了额外的代码来设置自定义 SslSocketFactory 并且一切正常!
所以原因是
it creates a new connection without using the one you created
正如 Jonatan 所说...这是我的一个小错误。 :)