Spring Boot ElasticSearch SSL 信任配置

使用了 HTTPS 连接 Elasticsearch,但通常本地环境使用的是自签名证书,Java 默认会验证证书链,因此会出现 PKIX path building failed 等证书信任错误。

要解决“如何信任”的问题,有以下几种常见方案:


1. 将自签名证书导入 JVM 的信任库(推荐用于开发/测试)

步骤:

  1. 导出 Elasticsearch 的证书(以 PEM 格式为例)

    openssl s_client -connect localhost:9200 -showcerts </dev/null 2>/dev/null | \
    openssl x509 -outform PEM > elastic-cert.pem
    
  2. 导入到 Java 的 cacerts 信任库

    keytool -import -alias elasticsearch -keystore $JAVA_HOME/lib/security/cacerts \
            -file elastic-cert.pem -storepass changeit -noprompt
    

    默认密码是 changeit,若使用自定义信任库请替换路径。

  3. 重启应用,证书即被信任。


2. 使用自定义 TrustStore(更灵活)

在 Spring Boot 中配置专用信任库:

  1. 创建自己的 truststore

    keytool -import -alias elasticsearch -keystore mytruststore.jks \
            -file elastic-cert.pem -storepass mypassword
    
  2. application.ymlapplication.properties 中指定

    spring.elasticsearch.restclient.ssl.truststore=classpath:mytruststore.jks
    spring.elasticsearch.restclient.ssl.truststore-password=mypassword
    

    注意:Spring Boot 2.x 中配置项为 spring.elasticsearch.restclient.ssl.*,如果是 Spring Data Elasticsearch 4.x+ 使用 RestClient,配置方式可能略有不同。

    如果是 Spring Boot 3.x 且使用 RestClient 自动配置,可以添加:

    spring.elasticsearch.ssl.bundle=my-bundle
    spring.elasticsearch.ssl.bundle.my-bundle.truststore.location=classpath:mytruststore.jks
    spring.elasticsearch.ssl.bundle.my-bundle.truststore.password=mypassword
    

3. 禁用 SSL 验证(仅限开发环境,极不推荐生产)

创建 RestClient 自定义配置,绕过证书校验:

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;

@Configuration
public class ElasticsearchConfig extends ElasticsearchConfiguration {

    @Override
    public ClientConfiguration clientConfiguration() {
        return ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .usingSsl(buildSSLContext())
                .withBasicAuth("elastic", "2DwqxCaVFFWhXBdvk+6x")
                .build();
    }

    private SSLContext buildSSLContext() {
        try {
            return SSLContextBuilder.create()
                    .loadTrustMaterial((chain, authType) -> true) // 信任所有证书
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

同时需要配置禁用主机名验证(可选):

.withHostnameVerifier(NoopHostnameVerifier.INSTANCE)

4. 使用环境变量或启动参数(临时绕过)

在 JVM 启动时添加:

-Djavax.net.ssl.trustStore=/path/to/mytruststore.jks \
-Djavax.net.ssl.trustStorePassword=mypassword

总结

方案 适用场景 安全性
导入 JVM 信任库 开发/测试环境,固定机器 中等,需管理证书
自定义 TrustStore 可移植,分环境配置 中等
禁用 SSL 验证 仅开发调试,快速验证 极低,禁止用于生产
JVM 启动参数 容器或脚本启动时统一设置 中等

建议在开发环境使用方案 1 或 2,生产环境务必使用正式的 CA 签发证书并正确配置信任链。