Micrometer 与基于 SSL 的 Elasticsearch

发布于 2025-01-10 21:18:11 字数 4224 浏览 0 评论 0原文

我正在尝试将 Micrometer 与基于 SSL 的 Elasticsearch 结合使用。

我使用 Micrometer 版本 1.8.0、Elasticsearch 版本 7.16.3 和 OpenJDK 11.0.2 。

因为我知道不可能使用内置配置(链接 )我尝试注入一个自定义的 HttpUrlConnectionSender ,如以下类 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 Boot 注入了该类,以便我可以应用所需的配置,但出现以下错误:

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,但错误仍然发生。

有人对如何修复它有任何建议吗?谢谢

I'm trying to use Micrometer with Elasticsearch over SSL.

I use Micrometer in version 1.8.0, Elasticsearch in version 7.16.3 and OpenJDK 11.0.2 .

Because I know that it's not possible to use a built-in configuration (link) I tried to inject a custom HttpUrlConnectionSender as in the following 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();
    }
}

that I injected with Spring Boot so I can apply the desired configuration, but I got the following error:

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
...

The server certificate and the client truststore are valid because I already used them with success.
I also tried to force a specific version of the TLS protocol during the handshake phase: TLSv1.3 and TLSv1.2 but the error still occurs.

Anyone have any suggestions on how to fix it? thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜中书 2025-01-17 21:18:11

检查 super.send 的作用,它会创建一个新连接,而不使用您创建的连接。我不建议使用自签名证书和自定义信任库,但您可以使用设置默认的 HostnameVerifier
HttpsURLConnection.setDefaultHostnameVerifier

由于这是静态的,因此它将适用于所有 HttpsURLConnection 实例,因此您无需向 Micrometer 中注入任何内容。

正确的解决方案是使用非自签名证书或适当的信任库(例如:通过 javax.net.ssl.trustStore)。

Check what super.send does, it creates a new connection without using the one you created. I'm not recommending using a self-signed cert and a custom truststore but you can set a default HostnameVerifier using
HttpsURLConnection.setDefaultHostnameVerifier.

Since this is static, it will work for all HttpsURLConnection instances so you don't need to inject anything into Micrometer.

The right solution would be either using a non-self-signed cert or a proper truststore (e.g.: via javax.net.ssl.trustStore).

挖鼻大婶 2025-01-17 21:18:11

我做了一个测试,对我发布的代码进行了简单的更改,并解决了它:
我复制了 super.send() 方法的所有代码,添加了额外的代码来设置自定义 SslSocketFactory ,一切正常!

所以原因是

它会创建一个新连接,而不使用您创建的连接

正如乔纳坦所说......这是我的一个小错误。 :)

I did a test with a simple change to the code I had posted and I solved it:
I copied all code of the super.send() method, adding the additional code to set the custom SslSocketFactory and all was OK!

so the reason was that

it creates a new connection without using the one you created

as Jonatan said... a my trivial mistake. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文