java-使用keytool信任自签证书,需要重启

目前我司的技术栈是Java和Python,且都调用第三方的服务,因此需要mock第三方的服务以便开发测试使用。之前已整理过[Python requests信任自签证书的问题]。(https://blog.csdn.net/windy135/article/details/79861209)因此这次需要再Java中mock第三方服务。

java官方文档:
1、使用keytool工具生成证书,然后将cer文件给mock 服务器:(即本文的反向解决办法)
https://docs.oracle.com/cd/E19798-01/821-1841/gjrgy/
2、关于keytool的官方说明:
https://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html

If keytool fails to establish a trust path from the certificate to be imported up to a self-signed certificate (either from the keystore or the "cacerts" file), the certificate information is printed out, and the user is prompted to verify it, e.g., by comparing the displayed certificate fingerprints with the fingerprints obtained from some other (trusted) source of information, which might be the certificate owner himself/herself. Be very careful to ensure the certificate is valid prior to importing it as a "trusted" certificate! -- see WARNING Regarding Importing Trusted Certificates. The user then has the option of aborting the import operation. If the -noprompt option is given, however, there will be no interaction with the user.

可以理解为从jdk1.6开始,keytool工具支持导入生成好的自签名证书。

下面说一下探索路径

1、已有RSA:2048 -x509自签证书,因此想着将这个证书导入jdk中即可;
2、因为我司使用的容器部署,方法:

存放证书:echo -e "${nginx.crt}" > $JAVA_HOME/jre/lib/security/cacerts
打到证书库:keytool -import -trustcacerts -alias nginx -file nginx.crt -keystore cacerts -storepass changeit -keyalg RSAs -noprompt

3、于是乎,先在docker中测试了一波,成功打进证书,postman请求, 缺收到了如下报错:

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

于是怀疑JVM在启动的时候会先把cacerts证书加载到虚拟机中,因此可能需要重启;
4、将2中内容写入dockerfile,执行gitlab-ci,却发现了如下错误:
Error Importing SSL certificate : Not an X.509 Certificate
此时有点慌(毕竟容器中是测试通过的,但是这里却失败了),想着是不是因为还有别的校验机制,一场徒劳的验证就此开始了:

1、首先怀疑证书生成算法有问题,校验证书 openssl x509 -in shouqianba.crt -text,信息都对;
2、试图尝试另一条路,根据证书公私钥生成p12文件,再将p12转为keystore,然后再keytool导入证书,发现还是Not an X.509 Certificate失败;(这一步的)
3、于是继续Google,终于发现[https://stackoverflow.com/questions/9889669/error-importing-ssl-certificate-not-an-x-509-certificate](https://stackoverflow.com/questions/9889669/error-importing-ssl-certificate-not-an-x-509-certificate)中的描述:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190617090901860.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dpbmR5MTM1,size_16,color_FFFFFF,t_70)
因此将2中的echo命令中多余的空格去掉,X.509 Certificate 验证通过。至此证书问题解决。(其实一开始就不应该怀疑jdk有别的验证,毕竟docker中验证过)

4、重启服务后,调用mock服务通过。
5、ci流程 -开箱即用:关于区分测试环境和线上环境的问题,不同项目做法不同,dockerfile和k8s deployment中都可一区环境,可参考:
k8s(根据文件区分环境,可以设置lifecycle): https://stackoverflow.com/questions/39436845/multiple-command-in-poststart-hook-of-a-container
dockerfile(一般是根据env变量区分,首先要找到ENV变量):
https://stackoverflow.com/questions/43654656/dockerfile-if-else-condition-with-external-arguments

简明步骤:(jdk1.6及以上,keytool支持将crt证书秘钥直接导入证书库)

1、$JAVA_HOME/jre/lib/security路径下存放着jdk校验自签证书的一些规则:

ssl.KeyManagerFactory.algorithm=SunX509
ssl.TrustManagerFactory.algorithm=PKIX
jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224

2、按照格式生成自签证书:
sudo openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
如果需要验证证书是否损坏,可以使用OpenSSL检查下:
openssl x509 -in shouqianba.crt -text
3、将生成好的nginx.crt证书拷贝到$JAVA_HOME/jre/lib/security路径下,完后使用keytool工具将证书打到$JAVA_HOME/jre/lib/security/cacerts
keytool -import -trustcacerts -alias nginx -file nginx.crt -keystore cacerts -storepass changeit -keyalg RSAs -noprompt
说明:keytool默认密码是changeit; -noprompt默认选择yes,不用交互输入。
4、由于该证书在 JVM 启动的时候加载,那时还没有新服务的证书,因此需要中期服务,才能生效。

以上四个步骤便能实现一个mock域名的ssl证书验证问题。

参考:
https://stackoverflow.com/questions/9889669/error-importing-ssl-certificate-not-an-x-509-certificate
https://stackoverflow.com/questions/39436845/multiple-command-in-poststart-hook-of-a-container
https://stackoverflow.com/questions/43654656/dockerfile-if-else-condition-with-external-arguments

关于不重启java-web,在不重启 JVM 的情况下重新加载证书文件的解决办法可参考:
https://blog.csdn.net/defonds/article/details/83061232

猜你喜欢

转载自blog.csdn.net/windy135/article/details/92562923
今日推荐