use*_*806 5 java mysql ssl amazon-rds spring-boot
我有一个 Spring Boot 应用程序,我试图从中连接到 AWS RDS 上的 MySQL。但是我遇到以下错误的问题:
localhost-startStop-1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
Run Code Online (Sandbox Code Playgroud)
为 ssl 握手启用调试后,我看到该CertificateRequest步骤Cert Authorities:为空。根据我的理解,这是客户端(spring boot 应用程序)需要向服务器(mysql db)提交证书的部分。
Certificate Request 步骤 - 服务器将从客户端发出证书请求。*** Certificate chain,这是客户端发送到服务器的证书。在这种情况下,对我来说,它正在发送keyStore_cert.jks.到目前为止我认为的问题:
服务器(mySQL db)不知道客户端(我的应用程序)正在发送的这个证书(我的 keyStore_cert.jks)。但是,我的印象是除非您REQUIRE X509为用户设置,否则不需要客户端证书。
问题:
keyStore_cert.jks/ 中添加任何内容trustStore_cert.jks吗?这些是我的设置和我尝试过的。
jdbc:mysql://<host>:<port>/<db_name>?useLegacyDatetimeCode=false&verifyServerCertificate=true&useSSL=true&requireSSL=trueALTER USER '<my_db_user>'@'%' require SSL;
GRANT USAGE ON <db_name>.* TO '<my_db_user>'@'%' REQUIRE SSL;
Run Code Online (Sandbox Code Playgroud)
keytool -import -keystore trustStore_cert.jks -storepass <trustStore_password> -alias "awsrds-us-east1" -file rds-ca-2015-us-east-1.pem-Djavax.net.ssl.keyStore=path/keyStore_cert.jks
-Djavax.net.ssl.keyStorePassword=<keyStore_password>
-Djavax.net.ssl.trustStore=path/trustStore_cert.jks
-Djavax.net.ssl.trustStorePassword=<trustStore_password>
Run Code Online (Sandbox Code Playgroud)
Host: <host>
Port: <port>
User: <user>
SSL: enabled with DHE-RSA-AES128-SHA
Run Code Online (Sandbox Code Playgroud)
SSL connection error: CA certificate is required if ssl-mode is VERIFY_CA or VERIFY_IDENTITY。这是有道理的,因为我没有为 CA 文件指定任何内容。握手步骤(将省略一些日志。):
*** ClientHello, TLSv1.1 (seems okay)
***
*** ServerHello, TLSv1.1 (seems okay)
***
*** Certificate chain (has the root key)
chain [0] = [
[
Version: V3
Subject: C=US, ST=Washington, L=Seattle, O=Amazon.com, OU=RDS, CN=**<my_rds_name>abcd.us-east-1.rds.amazonaws.com**
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
...
...
chain [1] = [ (has the us-east-1 key)
[
Version: V3
Subject: CN=Amazon RDS us-east-1 CA, OU=Amazon RDS, O="Amazon Web Services, Inc.", L=Seattle, ST=Washington, C=US
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
...
...
***
Found trusted certificate:
[
[
Version: V3
Subject: CN=Amazon RDS us-east-1 CA, OU=Amazon RDS, O="Amazon Web Services, Inc.", L=Seattle, ST=Washington, C=US
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
...
...
*** CertificateRequest (the Authorities are empty)
Cert Types: RSA, DSS, ECDSA
Cert Authorities:
<Empty>
*** ServerHelloDone
matching alias: <my keyStoreAlias>
*** Certificate chain (seems entries from my own key Store)
chain [0] = [
[
Version: V3
Subject: CN=<the CN on my keyStore>, OU=Web Servers, O=Company , C=US
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
***
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1.1 (seems okay)
*** CertificateVerify (seem okay)
*** Finished
verify_data: { 50, 89, 33, 202, 193, 158, 226, 114, 128, 50, 198, 250 }
***
Run Code Online (Sandbox Code Playgroud)
在与 AWS RDS Support 合作后,我得到了问题的原因以及解决方法的解释。
只是为了澄清,这个问题主要仅在您将自己的密钥库作为 JVM 参数的一部分传递时才会出现。像这样的东西:
-Djavax.net.ssl.keyStore=path/keyStore_cert.jks
-Djavax.net.ssl.keyStorePassword=<keyStore_password>
Run Code Online (Sandbox Code Playgroud)
RDS 是一项托管服务,他们没有办法(目前)将特定的客户端证书加载到服务器中。这意味着他们无法在数据库配置级别传递特定证书。通常,如果您要建立自己的 MY SQL 服务器,这将是可能的。在该服务器的配置文件中,您可以指定客户端/服务器证书。因此,RDS 无法验证客户端提供的证书。
如果您要传递具有密钥对条目(作为 JVM 参数或其他方式)的密钥库,则在 SSL 握手期间,客户端身份验证步骤将失败。这是数据库中的预期行为。RDS 不能限制自己在初始连接期间为客户端验证(或不验证)加载在客户端字段中的文件。因此,如果传递了密钥库,服务器将尝试将证书密钥与现有 CA 文件匹配,如果不匹配,则不允许连接。
解决方案是要么根本不传递密钥库,要么传递一个空白的密钥库(一个没有密钥对,只有可信证书条目,或者一个只是空白的)。
如果您选择不传递密钥库,则不要指定这些属性
-Djavax.net.ssl.keyStore= & -Djavax.net.ssl.keyStorePassword=。并构建数据库连接的URL是这样的:
-Ddb_jdbc_url=jdbc:mysql://<host>:<port>/<db_name>?useLegacyDatetimeCode=false&verifyServerCertificate=true&useSSL=true&requireSSL=true。您仍然需要提供信任库。查看底部了解更多信息。
传递黑色密钥库或(或传递密钥库字段中的信任库)您可以为密钥库和信任库 JVM 参数传递您想要的任何内容。对于 URL,您可以像这样构造它:
-Ddb_jdbc_url=jdbc:mysql://<host>:<port>/<db_name>?
useLegacyDatetimeCode=false&verifyServerCertificate=true&useSSL=true&requireSSL=true
&clientCertificateKeyStoreUrl=file:/user/documents/projects/trust-store-rds.jks
&clientCertificateKeyStorePassword=<password>
&clientCertificateKeyStoreType=JKS
&trustCertificateKeyStoreUrl=file:/user/documents/projects/trust-store-rds.jks
&trustCertificateKeyStorePassword=<password>
&trustCertificateKeyStoreType=JKS
Run Code Online (Sandbox Code Playgroud)
请注意,对于两者trustCertificateKeyStoreUrl,clientCertificateKeyStoreUrl我正在传递相同的文件。
请注意,您还需要配置所有前面的步骤:
CREATE USER 'my_user'@'%' IDENTIFIED BY 'my_password';
ALTER USER 'my_user'@'%' REQUIRE SSL;
GRANT USAGE ON *.* TO 'my_user'@'%' REQUIRE SSL ;
Run Code Online (Sandbox Code Playgroud)
keytool -import -keystore trust-store-rds.jks -storepass changeit -noprompt alias "aws-rds-root" -file rds-ca-2015-root.pem
keytool -import -keystore trust-store-rds.jks -storepass changeit -noprompt -alias "aws-rds-us-east-1" -file rds-ca-2015-us-east-1.pem
Run Code Online (Sandbox Code Playgroud)