JDBC+SSL:将 CA 证书、客户端证书和客户端捆绑到一个密钥库文件中
JDBC+SSL: Bundling a CA cert, client cert and client into a single keystore file
Google Cloud SQL 通过为您生成服务器 ca-cert.pem
、client-cert.pem
和 client-key.pem
来支持 SSL 连接。我已经通过以下步骤让我的 Java 客户端连接到 Cloud SQL:
1) 将服务器 CA 证书导入到信任库文件中:
keytool -import -alias mysqlServerCACert -file ca-cert.pem -keystore truststore
2) 将客户端证书和客户端密钥捆绑到一个 pkcs12 文件中:
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out client.p12 -name clientalias -CAfile ca-cert.pem
3) 将 pkcs12 导入密钥库文件:
keytool -importkeystore -deststorepass keystore -destkeystore keystore -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass keystore -alias clientalias
4) 告诉 JVM 使用我的信任库和密钥库:
-Djavax.net.ssl.keyStore=/path/to/my/keystore \
-Djavax.net.ssl.keyStorePassword=keystore \
-Djavax.net.ssl.trustStore=/path/to/my/truststore \
-Djavax.net.ssl.trustStorePassword=truststore
这一切都有效,但不幸的是它排除了来自其他客户端库的出站 HTTPS 连接——在我的例子中,Firebase java 客户端库。问题是我的 -Djavax.net.ssl.trustStore
参数覆盖了与 JDK.
捆绑在一起的默认 cacerts
文件
我似乎有两个选择。一种不理想的选择是将我的服务器 CA 证书导入到 JDK 的 cacerts
文件中,在每台生产和开发机器上,使用 OS-specific 和 JDK-特定于版本的命令。这个选项对于实际的生产设置来说似乎很笨重。
另一种选择是将我的服务器 CA 证书和客户端证书捆绑到一个(本地)信任链中,然后 Java 将使用它来验证我的客户端密钥。从我读过的内容来看,我很确定这是可能的,但我不知道所需的咒语。
我的猜测是,我应该使用单个 openssl
命令创建一个包含我的服务器 CA 证书、客户端证书和客户端密钥的 pkcs12 包,顺序正确,然后使用 keytool
将其导入新的密钥库。我会省略 -D.../trustStore
JVM 参数,只指定密钥库参数。 Java 将为我的云 SQL 客户端密钥使用本地 CA 信任链,但会退回到全局 cacerts
文件进行所有其他 SSL 协商。
这可能吗?如果作为单个 pkcs12 不能直接实现,那么是否有一些其他步骤可以将它们全部放入单个密钥库中,绕过对信任库的需要?
将默认的 JRE cacerts
文件复制到新的信任库并将服务器证书添加到其中。用于所有客户。将此作为构建步骤并在每次升级 JRE 时重复,这样您就不会错过默认 cacerts.
中的证书更改
当然,如果服务器证书由公认的 CA 正确签名,则无需将其导入任何地方,或使用自定义信任库。如果它不是由公认的 CA 签署的,它应该是。
Google Cloud SQL 通过为您生成服务器 ca-cert.pem
、client-cert.pem
和 client-key.pem
来支持 SSL 连接。我已经通过以下步骤让我的 Java 客户端连接到 Cloud SQL:
1) 将服务器 CA 证书导入到信任库文件中:
keytool -import -alias mysqlServerCACert -file ca-cert.pem -keystore truststore
2) 将客户端证书和客户端密钥捆绑到一个 pkcs12 文件中:
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out client.p12 -name clientalias -CAfile ca-cert.pem
3) 将 pkcs12 导入密钥库文件:
keytool -importkeystore -deststorepass keystore -destkeystore keystore -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass keystore -alias clientalias
4) 告诉 JVM 使用我的信任库和密钥库:
-Djavax.net.ssl.keyStore=/path/to/my/keystore \
-Djavax.net.ssl.keyStorePassword=keystore \
-Djavax.net.ssl.trustStore=/path/to/my/truststore \
-Djavax.net.ssl.trustStorePassword=truststore
这一切都有效,但不幸的是它排除了来自其他客户端库的出站 HTTPS 连接——在我的例子中,Firebase java 客户端库。问题是我的 -Djavax.net.ssl.trustStore
参数覆盖了与 JDK.
cacerts
文件
我似乎有两个选择。一种不理想的选择是将我的服务器 CA 证书导入到 JDK 的 cacerts
文件中,在每台生产和开发机器上,使用 OS-specific 和 JDK-特定于版本的命令。这个选项对于实际的生产设置来说似乎很笨重。
另一种选择是将我的服务器 CA 证书和客户端证书捆绑到一个(本地)信任链中,然后 Java 将使用它来验证我的客户端密钥。从我读过的内容来看,我很确定这是可能的,但我不知道所需的咒语。
我的猜测是,我应该使用单个 openssl
命令创建一个包含我的服务器 CA 证书、客户端证书和客户端密钥的 pkcs12 包,顺序正确,然后使用 keytool
将其导入新的密钥库。我会省略 -D.../trustStore
JVM 参数,只指定密钥库参数。 Java 将为我的云 SQL 客户端密钥使用本地 CA 信任链,但会退回到全局 cacerts
文件进行所有其他 SSL 协商。
这可能吗?如果作为单个 pkcs12 不能直接实现,那么是否有一些其他步骤可以将它们全部放入单个密钥库中,绕过对信任库的需要?
将默认的 JRE cacerts
文件复制到新的信任库并将服务器证书添加到其中。用于所有客户。将此作为构建步骤并在每次升级 JRE 时重复,这样您就不会错过默认 cacerts.
当然,如果服务器证书由公认的 CA 正确签名,则无需将其导入任何地方,或使用自定义信任库。如果它不是由公认的 CA 签署的,它应该是。