You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用IAM认证连接AWS RDS MySQL时遇证书链信任锚错误

问题:Java 17通过IAM认证连接AWS RDS MySQL时SSL握手失败

我正在编写基于Java 17的应用,尝试通过IAM认证连接AWS RDS MySQL实例,采用SSL连接方式,先后尝试了以下官方证书包:

  • global-bundle.pem
  • us-west-2-bundle.pem(RDS实例位于us-west-2区域)
  • rds-ca-2019-us-west-2.pem(示例代码使用,但未在SSL文档中列出)

简化后的核心代码如下:

X509Certificate x509Cert;
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
URL url = new File("c:\\users\\me\\documents\\global-bundle.pem").toURI().toURL();
try (InputStream certInputStream = url.openStream()) {
    x509Cert = (X509Certificate) certFactory.generateCertificate(certInputStream);
}

File keyStoreFile = File.createTempFile("sys-connect-via-ssl-test-cacerts", ".jks");
try (FileOutputStream fos = new FileOutputStream(keyStoreFile.getPath())) {
    KeyStore ks = KeyStore.getInstance("JKS", "SUN");
    ks.load(null);
    ks.setCertificateEntry("rootCaCertificate", x509Cert);
    ks.store(fos, "changeit".toCharArray());
}

System.setProperty("javax.net.ssl.trustStore", keyStoreFile.getPath());
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

BasicAWSCredentials awsCredentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);

RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder()
        .credentials(new AWSStaticCredentialsProvider(awsCredentials)).region("us-west-2").build();
String authToken = generator.getAuthToken(GetIamAuthTokenRequest.builder()
        .hostname(RDS_INSTANCE_HOSTNAME).port(3306).userName(DB_USER).build());

Properties mysqlConnectionProperties = new Properties();
mysqlConnectionProperties.setProperty("verifyServerCertificate","true");
mysqlConnectionProperties.setProperty("useSSL", "true");
mysqlConnectionProperties.setProperty("user",DB_USER);
mysqlConnectionProperties.setProperty("password",authToken);

DriverManager.getConnection("jdbc:mysql://" + RDS_INSTANCE_HOSTNAME + ":3306", mysqlConnectionProperties);

调用DriverManager.getConnection(...)时触发错误,核心异常为:

Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors

更换三种证书包后问题依旧。查阅资料得知该错误通常需根证书+区域中间证书,但已确认所用bundle包包含两类证书,仍无法解决,请问故障原因是什么?


故障原因及解决方案

1. 证书加载不完整:仅读取了bundle中的第一个证书

你的代码使用certFactory.generateCertificate(certInputStream)只会加载PEM bundle文件里的第一个证书,但AWS的bundle包包含多个证书(根证书、中间证书),这种方式会丢失后续证书,导致证书链不完整,最终无法通过SSL验证。

正确的加载方式是使用generateCertificates方法读取所有证书,并全部加入密钥库:

// 替换原证书加载逻辑
Collection<? extends Certificate> certs;
try (InputStream certInputStream = url.openStream()) {
    certs = certFactory.generateCertificates(certInputStream);
}

// 将所有证书添加到密钥库
int certIndex = 0;
for (Certificate cert : certs) {
    ks.setCertificateEntry("ca-cert-" + certIndex++, cert);
}

2. 密钥库配置冗余(Java 17环境)

Java 17中无需指定SUN作为JKS密钥库的提供者,直接使用默认实现即可,简化代码:

KeyStore ks = KeyStore.getInstance("JKS"); // 移除第二个参数

3. JDBC连接属性优化

建议在MySQL连接属性中添加requireSSL=true强制SSL连接,确保使用的MySQL驱动版本为8.0+(IAM认证对驱动版本有要求):

mysqlConnectionProperties.setProperty("requireSSL", "true");

4. 验证RDS实例的CA版本匹配

登录AWS控制台查看你的RDS实例的CA证书标识符(如rds-ca-2023),确认下载的bundle包与该版本对应。如果实例使用的是旧版CA,需下载对应年份的区域bundle包。

5. 避免覆盖系统全局信任库(可选)

直接通过系统属性设置信任库会影响应用中其他SSL连接,建议为MySQL连接单独配置SSL上下文:

// 基于加载好的密钥库构建SSL上下文
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

// 将SSL上下文传递给MySQL驱动
mysqlConnectionProperties.setProperty("sslSocketFactory", sslContext.getSocketFactory().getClass().getName());

内容的提问来源于stack exchange,提问作者pacoverflow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 20:15:05