使用Java 8在嵌入式Tomcat 8.5上启用TLS握手的可观察性(日志记录/度量)

使用Java 8在嵌入式Tomcat 8.5上启用TLS握手的可观察性(日志记录/度量),java,spring-boot,tomcat,ssl,embedded-tomcat-8,Java,Spring Boot,Tomcat,Ssl,Embedded Tomcat 8,我们正在运行SpringBootAPI,在API中终止TLS。有几次,我们观察到,由于有人创建了许多连接(合法或错误地,因为被拒绝的客户端证书)或没有使用TLS恢复,导致大量搜索后CPU使用过度 为了防止将来进行这些冗长而昂贵的搜索,我们希望记录握手失败或成功的时间,以及为什么以及是否正在使用会话恢复 我们并不特别依赖于当前的堆栈,升级到不同的服务器(如Undertow或WebFlux)和/或新版本的Java也可以。同样,我们可以使用APR、NIO或本机绑定来实现这些目标 以下其他问题表明,目前

我们正在运行SpringBootAPI,在API中终止TLS。有几次,我们观察到,由于有人创建了许多连接(合法或错误地,因为被拒绝的客户端证书)或没有使用TLS恢复,导致大量搜索后CPU使用过度

为了防止将来进行这些冗长而昂贵的搜索,我们希望记录握手失败或成功的时间,以及为什么以及是否正在使用会话恢复

我们并不特别依赖于当前的堆栈,升级到不同的服务器(如Undertow或WebFlux)和/或新版本的Java也可以。同样,我们可以使用APR、NIO或本机绑定来实现这些目标

以下其他问题表明,目前没有现成的解决方案。他们建议扩展或更改NIO适配器的级别以进行调试。这些解决方案感觉很脆弱,我想知道是否有一种基于事件或回调的更可扩展的机制。或者,我们可以从Java中启用握手日志,但这些日志非常冗长,这样做会导致严重的性能损失

更新1:
我尝试过使用定制的SSLServerSocketFactory。
sun.security.ssl.SSLServerSocketFactoryImpl
在绑定时返回
sun.security.ssl.SSLServerSocketImpl
,在接受时返回尼斯
SSLSocket
。我可以将accept方法包装为始终添加一个完成处理程序。唯一的缺点是:
sslserversocketfactorympl
是最终版本,所以我不能直接包装它。这意味着我需要复制大量代码,但它仍然只能提供成功握手的指标。复制代码将是一个维护负担,因为这是特定于JRE的代码。

我的答案可能不是您所期望的,但这是我自己会做的

首先,我从不在自定义软件上启用SSL。既不是Java,也不是C#,也不是Python,也不是Javascript。在我所有的解决方案中,它们都运行在纯HTTP上

我委托给NGINX的所有TLS内容。这是可靠的。它很快。它有很多选择。它有多功能和详细的日志。它有一些基本的访问控制和DDoS保护。它封装了部署的细节,并为多个提供的服务提供了一个门面

开销很小,即使在普通硬件上也运行良好

您需要两个特性:反向代理和详细日志记录

最简单的配置文件如下所示:

server {
        listen 443 ssl;

        server_name example.com;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;

        location / {
                # Transfer all request to the actual server using HTTP
                proxy_pass http://<server-in-intranet>:12345;
                proxy_set_header Host $host;
        }
        # TLS handshake errors are reported at the info level
        error_log /var/log/nginx/example.com/error.log info;
        # Extra ideas about SSL logging: 
        #   https://docs.nginx.com/nginx/admin-guide/monitoring/logging/#tls_sample

        # The certificates from Let's Encrypt are installed by Certbot
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
}
服务器{
听443ssl;
server_name example.com;
ssl_协议TLSv1 TLSv1.1 TLSv1.2;
地点/{
#使用HTTP将所有请求传输到实际服务器
代理传递http://:12345;
代理设置头主机$Host;
}
#TLS握手错误在信息级别报告
error\u log/var/log/nginx/example.com/error.log info;
#关于SSL日志记录的其他想法:
#   https://docs.nginx.com/nginx/admin-guide/monitoring/logging/#tls_sample
#来自Let's Encrypt的证书由Certbot安装
ssl_certificate/etc/letsencrypt/live/example.com/fullchain.pem;#由Certbot管理
ssl_certificate_key/etc/letsencrypt/live/example.com/privkey.pem;#由Certbot管理
}
通过此配置,服务器通过HTTPS为实际服务器的内容提供服务,而实际服务器是纯HTTP,该服务器运行在内部网的某处


使用这个设置,我运行用Go、Javascript和Python编写的服务器,这些服务器运行在不同的机器上,但在单个访问点下收集,例如,

这是一个单独的服务器还是负载平衡器后面的一组服务器

您可以考虑“重新部署”服务器,使您拥有相同配置的副本,但使用java opt调试SSL:启用握手。 现在,在负载平衡器上,您将一部分流量定向到调试服务器,以对您感兴趣的活动进行采样

或者,您可以在同一台服务器上的不同端口上部署另一个tomcat实例,该端口已启用调试。(这比你提到的服务器在请求增加时可能已经陷入麻烦的情况下增加的负载要少。)

所以,也许你没有负载平衡器,但你可能有防火墙,看看你的防火墙是否有状态,是否可以为你“分割流量”

如果当前服务器是linux服务器,您可以在我上面提到的“双本地安装”示例中使用iptables来完成此操作。大概是这样的:

无法绕过复杂的解决方案

如果你没有一个负载均衡器,你可能需要考虑它,因为它为你提供了很多灵活性来处理各种情况,而不仅仅是这个。 祝你好运


David

例如事件或回调:这已经被问到了,但我记得没有任何好的答案。您还提供了提到的解决方案(扩展JSSE,实现工厂)@EugèneAdell,事实上,它以前曾被问过。但一个问题是一年前提出的,另一个问题起源于2008年。这段时间可能会发生很多事情,关键是JSSE设计用于将应用程序与底层SSL/TLS处理隔离开来。这是一个好主意,因为它使整个过程可以与不同的提供者进行插拔,但无法轻松访问回拨的副作用是对统计数据收集(协议、客户端使用的密码套件、错误原因)的惩罚。设计师不想知道为什么客户端不能与服务器协商,他们认为这些客户端是旧的/坏的,不有趣。我检查了OpenSSL可以做什么,但并没有更好。有趣的是,它确实存在。如果我能自己融入其中,我至少可以看到成功的连接,通过保持t