[英]Disable mySQL RDS client authentication
I am trying to connect to a mySQL RDS DB from a java SpringBoot application.我正在尝试从 java SpringBoot 应用程序连接到 mySQL RDS 数据库。 I have made the required changes on the DB.
我已经对数据库进行了必要的更改。
ALTER USER 'my_app'@'%' require SSL;
GRANT USAGE ON *.* TO 'my_app'@'%' REQUIRE SSL;
However, the connection does not happen.但是,连接不会发生。 It is failing at the client authentication part.
它在客户端身份验证部分失败。 The server (mysql db) is not able to authenticate the client (java application).
服务器(mysql db)无法对客户端(java 应用程序)进行身份验证。
Question:题:
How do I disable client authentication?如何禁用客户端身份验证? Based on the documentation it should be disabled unless you do "REQUIRE X509".
根据文档,除非您执行“REQUIRE X509”,否则应该禁用它。 So, I am confused about that.
所以,我对此感到困惑。 Documentation I am referring is this: https://dev.mysql.com/doc/refman/8.0/en/alter-user.html .
我指的文档是这样的: https : //dev.mysql.com/doc/refman/8.0/en/alter-user.html 。
How can I make this work, using both a keyStore and trustStore?我怎样才能使用 keyStore 和 trustStore 来完成这项工作?
More info:更多信息:
I have also imported the AWS root and regional certificate into my trust store.我还将 AWS 根证书和区域证书导入到我的信任存储中。 At this point (without a keyStore passed as JVM), the connection happens fine.
此时(没有作为 JVM 传递的 keyStore),连接正常。
However, in my application I need to use a keyStore as well.但是,在我的应用程序中,我还需要使用 keyStore。
-Djavax.net.ssl.keyStore=path/keyStore.jks
-Djavax.net.ssl.keyStorePassword=<keyStore_password>
When, I do this, the connection does not happen and the following error is thrown:当我这样做时,连接不会发生并抛出以下错误:
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
Adding the ssl handshake debug I see the following logs:添加 ssl 握手调试我看到以下日志:
*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Cert Authorities:
<Empty>
localhost-startStop-1, READ: TLSv1.1 Handshake, length = 4
*** ServerHelloDone
matching alias: mysqlrds
matching alias: client-nonprod
*** Certificate chain
chain [0] = [
It looks like it is failing at the part where the server (mysql DB) is trying to verify the client (java application).看起来它在服务器(mysql DB)尝试验证客户端(java应用程序)的部分失败了。 In the following steps the client (java application) needs to present a certificate to the server (mysql db).
在以下步骤中,客户端(java 应用程序)需要向服务器(mysql db)提供证书。
In the step above (CertificateRequest), the server is sending an empty "Cert Authorities".在上面的步骤 (CertificateRequest) 中,服务器正在发送一个空的“Cert Authorities”。 Which usually means that the server (mysql db) has an empty or not initialize trust store.
这通常意味着服务器(mysql db)有一个空的或未初始化的信任库。 The steps afterwards (Certificate chain), the client (java app) send to the server (mysql db) a certificate.
之后的步骤(证书链),客户端(java app)向服务器(mysql db)发送一个证书。 In this case the "keyStore_cert.jks".
在这种情况下,“keyStore_cert.jks”。 But the server, does not know about it and it throws and error on Handshake.
但是服务器不知道它,它在握手时抛出错误。
Sample Code:示例代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//1. Dowload my sql connector to a folder "jars". http://central.maven.org/maven2/mysql/mysql-connector-java/8.0.13/mysql-connector-java-8.0.13.jar
// This file and the jars folder are on the same folder (or level). Not inside one another.
//2. edit this file to have your settings. Name of the DB,URL,username,password,trustStore,keyStore,DB name, table name.
//3. compile the file: javac -cp ".:./jars/mysql-connector-java-8.0.13.jar" SampleCode.java
//4. run the program: java -cp ".:./jars/mysql-connector-java-8.0.13.jar" SampleCode
public class SampleCode {
public static void main(String[] args) {
Connection con;
try {
// TODO: replace with your settings.
System.setProperty("javax.net.ssl.trustStore", "path/resource/certs/trustStore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "trustStore_pass");
System.setProperty("javax.net.ssl.keyStore", "path/resource/certs/keyStore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "keyStore_pass");
System.setProperty("javax.net.debug", "ssl:handshake");
Class.forName("com.mysql.cj.jdbc.Driver");
// TODO: replace with your settings.
con = DriverManager.getConnection(
"jdbc:mysql://my_db_name.random_string.us-east-1.rds.amazonaws.com:3/my_db?useLegacyDatetimeCode=false&verifyServerCertificate=true&useSSL=true&requireSSL=true",
"my_app", "my_pass");
System.out.println(" connection successful \n");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM my_table "); // TODO: replace with yours.
while (rs.next()) {
System.out.println("id : " + rs.getString("id"));
}
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
Reference Materials:参考资料:
I faced this same error in an application where hibernate is used.我在使用休眠的应用程序中遇到了同样的错误。 Apparently RDS only does client authentication during a SSL handshake.
显然 RDS 仅在 SSL 握手期间进行客户端身份验证。 Instead of disabling client authentication because you need to use a separate key store for your application you can override the key store used for jdbc connection through connection properties.
您可以通过连接属性覆盖用于 jdbc 连接的密钥库,而不是禁用客户端身份验证,因为您需要为应用程序使用单独的密钥库。
Properties properties = new Properties();
properties.put("user", "my_app");
properties.put("password", "my_pass"); properties.put("clientCertificateKeyStoreUrl","file:path_to_rds_truststore_file");
properties.put("clientCertificateKeyStorePassword","password");
String url = "jdbc:mysql://localhost/mydatabase";
Connection con = DriverManager.getConnection(url, properties);
By doing the above you can override the keystore that will be used for establishing connection to RDS while using a separate system wide keystore.通过执行上述操作,您可以在使用单独的系统范围的密钥库时覆盖将用于建立与 RDS 的连接的密钥库。 Note that you need to set the properties every time you want to get a connection to the RDS instance.
请注意,每次想要连接到 RDS 实例时都需要设置这些属性。
As mentioned in your reference :正如您的参考文献中提到的:
Notice that when used together, the connection properties override the values set by the other two methods.
请注意,当一起使用时,连接属性会覆盖其他两种方法设置的值。 Also, whatever values set with connection properties are used in that connection only, while values set using the system-wide values are used for all connections (unless overridden by the connection properties).
此外,使用连接属性设置的任何值仅用于该连接,而使用系统范围值设置的值用于所有连接(除非被连接属性覆盖)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.