OpenLiberty 抛出 javax.net.ssl.SSLHandshakeException

OpenLiberty throws javax.net.ssl.SSLHandshakeException

我尝试在 Eclipse OpenJ9 VM 版本 1.8 上 运行 OpenLiberty (v20.0.0.1/wlp-1.0.36.cl200120200108-0300) 上的微服务(基于 Eclipse Microprofile)。0_242-b08 (en_US))

我运行服务器作为官方Docker镜像(open-liberty:kernel)

在我的服务中,我尝试通过 HTTPS 连接到另一个休息服务

Client client = ClientBuilder.newClient();
client.target("https://myservice.foo.com/").request(....);

这将引发以下异常:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: PKIX path building failed: 
        sun.security.provider.certpath.SunCertPathBuilderException: 
        unable to find valid certification path to requested target

我已经将特征 'transportSecurity-1.0' 和 'ssl-1.0' 添加到 server.xml 文件中:

<featureManager>
  <feature>jaxrs-2.1</feature>
  <feature>microProfile-2.2</feature>
  <feature>transportSecurity-1.0</feature>
  <feature>ssl-1.0</feature>
</featureManager>

我还像这样调整了 jvm.options 文件:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7777
-Dhttps.protocols=TLSv11,TLSv12
-Djdk.tls.client.protocols=TLSv11,TLSv12
-Dhttps.protocols=TLSv11,TLSv12
-Dcom.ibm.jsse2.overrideDefaultProtocol=TLSv11,TLSv12

但没有任何方法可以消除异常。

OpenLiberty 启用传出 SSL 连接的正确配置是怎样的?

默认情况下,Liberty 不信任 ssl 上的任何内容,因此除非您要连接的服务使用相同的 keystore/truststore 文件,或者您以其他方式将服务配置为以某种方式信任微服务,你可以得到那个例外。如果这是问题所在,那么在 messages.log 中也可能会看到类似的内容:

com.ibm.ws.ssl.core.WSX509TrustManager E CWPKI0823E:SSL 握手失败:SubjectDN [CN=localhost,OU=oidcdemo_client,O=ibm,C=us] 的签名者从主机 [本地主机:19443]。签名者可能需要添加到位于 SSL 配置别名 [defaultSSLConfig] 中的本地信任库 [/Users/tester/tmp/liberty/20003wlp/wlp/usr/servers/urlcheck/resources/security/key.p12]。来自 SSL 握手异常的扩展错误消息是:[PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效证书路径]。

此处记录了如何手动修补信任库,

https://www.ibm.com/support/knowledgecenter/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_add_trust_cert.html

但是在 docker 环境中您可能想要做的是修改您的图像以包含公共 keystore/truststore,或者从外部某处读取图像(例如 kubernetes 秘密)。默认情况下,每个 docker 图像都会创建自己唯一的 key/truststore,它们将无法 "talk" 通过 ssl。

如果您只需要与具有知名机构签署的证书的服务进行通信,您可以添加

ENV SEC_TLS_TRUSTDEFAULTCERTS=true

到您的 Dockerfile (20.0003+) 以启用它。

正如 Bruce 在上面的回答中提到的,默认情况下,Liberty 不信任任何证书。如果您正在建立从 Liberty 到服务器的传出连接,您需要将他们的证书添加到您配置的信任库中,或者如果远程端点使用的是来自知名 CA 的证书,则您需要信任 JRE 的 cacerts。

当您说您正在使用 Let's Encrypt 证书时,您的意思是远程端点正在使用它们,还是您的 Liberty 服务器正在使用它们?

如果远程端点是,大多数 JRE 的 cacerts 都会在他们的 cacerts 中包含 Let's Encrypt。如果 Liberty 服务器使用由 Let's Encrypt 签名的证书,除非您使用相互 SSL 身份验证,否则这对传出连接实际上没有影响。

仅供参考,如果您使用 Let's Encrypt in Liberty 签名的证书作为默认证书,我们将在几个版本中添加对 ACME 协议的内置支持。在这里查看进度:https://github.com/OpenLiberty/open-liberty/issues/9017