Windows环境下通过SSH隧道用Java连接DocumentDB遇SSL错误求助
DocumentDB Java连接SSL握手失败(PKIX路径问题)解决思路
核心问题分析
你遇到的PKIX路径构建失败+SSL握手超时,本质对应两个问题:JVM未信任DocumentDB的CA证书,且主机名验证不通过(因为SSH隧道映射到localhost,但证书绑定的是远程DocumentDB域名),和mongosh使用的--sslCAFile、--sslAllowInvalidHostnames参数直接相关。
具体解决步骤
1. 让JVM信任DocumentDB的CA证书
mongosh通过--sslCAFile指定了rds-ca.pem,Java需要把这个证书加入信任链,有两种实现方式:
方式一:导入到JVM系统信任库
用keytool命令将证书导入JRE默认信任库(Windows环境):
keytool -importcert -file rds-ca.pem -alias docdb-ca -keystore "%JAVA_HOME%\jre\lib\security\cacerts"
- 提示输入密码时,默认密码为
changeit - 确认导入时输入
y即可完成操作
方式二:代码中自定义加载证书(无需修改系统信任库)
在Java代码中直接加载rds-ca.pem,构建自定义SSL上下文,示例代码片段:
// 加载CA证书文件 CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream("rds-ca.pem")) { X509Certificate cert = (X509Certificate) cf.generateCertificate(fis); // 创建信任存储并添加证书 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null); trustStore.setCertificateEntry("docdb-ca", cert); // 初始化信任管理器 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); // 构建SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); }
2. 关闭主机名验证(对应mongosh的--sslAllowInvalidHostnames)
因为你通过SSH隧道连接localhost:27017,但证书绑定的是远程DocumentDB域名my-cluster.eu-west-3.docdb.amazonaws.com,JVM默认会验证主机名匹配,必须关闭该验证:
在MongoClientSettings的SSL配置中添加:
.applyToSslSettings(builder -> { builder.enabled(true) .invalidHostNameAllowed(true); // 允许不匹配的主机名 })
3. 完整的MongoClient配置示例
整合上述配置,完整连接代码如下:
import com.mongodb.client.MongoClients; import com.mongodb.client.MongoClient; import com.mongodb.MongoClientSettings; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; public class DocumentDBConnector { public static void main(String[] args) throws Exception { // 加载CA证书 CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert; try (FileInputStream fis = new FileInputStream("rds-ca.pem")) { cert = (X509Certificate) cf.generateCertificate(fis); } // 构建信任存储 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null); trustStore.setCertificateEntry("docdb-ca", cert); // 初始化信任管理器 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); // 创建SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); // 配置Mongo客户端 MongoClientSettings settings = MongoClientSettings.builder() .applyToSslSettings(sslBuilder -> { sslBuilder.enabled(true) .invalidHostNameAllowed(true); }) .sslContext(sslContext) .credential(MongoCredential.createCredential( "user", // 用户名 "admin", // 认证数据库(默认admin) "pwd".toCharArray() // 密码 )) .applyToClusterSettings(clusterBuilder -> clusterBuilder.hosts(Arrays.asList(new ServerAddress("localhost", 27017))) ) .build(); // 建立连接并测试 try (MongoClient client = MongoClients.create(settings)) { System.out.println("连接成功,数据库列表:"); client.listDatabaseNames().forEach(System.out::println); } } }
4. 排查网络及隧道状态
- 确认SSH隧道持续运行:
ssh -L 27017:my-cluster.eu-west-3.docdb.amazonaws.com:27017 ubuntu@my-ec2.com -N不能中断 - 测试本地端口连通性:用
telnet localhost 27017或Test-NetConnection localhost -Port 27017(PowerShell)验证端口是否开放 - 检查Windows防火墙:确保Java程序未被阻止访问localhost:27017
内容的提问来源于stack exchange,提问作者X6Entrepreneur
相关产品推荐
相关产品推荐

