Linux内核TLS和Nginx

在本文中,我将讨论通过将加密转移到操作系统的核心来加速TLS连接中内容分发的发展历史和当前技术水平,以及我对该方向的发展所做出的贡献。

背景


早在2015年,Netflix的Randall Stewart和Scott Long就在AsiaBSDCon2015 大会作了关于优化加密内容分发的演讲。该报告的主要信息是将数据加密转移到操作系统的内核,以减少内核空间和用户空间之间的数据副本数量,并使用优化的非阻塞sendfile()系统调用。事实证明,该主题非常有前途,已经在2016年Netdev 1.2大会上,Facebook的Dave Watson做了一个关于在Linux内核中创建TLS套接字的需求演示,而Mellanox的Boris Pismenny,Ilya Lesokhin和Liran Liss 做了一个演示。关于在网卡中使用TLS硬件加速的功能。Tempesta Technologies的发言人也在HighLoad ++ 2017上讨论了该主题。

Linux内核支持


所有这些对话的结果是内核TLS在Linux内核4.13(2017)中的出现,并支持TLSv1.2和AES128-GCM密码。最初,仅支持对传出流量的加密,后来在Linux内核4.17(2018)中出现了解密支持。在5.1版中,他们添加了对TLSv1.3和AES256-GCM的支持,在5.2版中,他们还添加了AES128-CCM密码(2019)。

用户空间支持


在上述所有报告中,都说只能在内核中放置有用数据的加密,并且所有TLS批准和控制消息都必须在用户空间中以相同的方式处理。为此,使用了OpenSSL的修改版本。但是,在公共领域发布报告时,没有关于需要对该知名库进行哪些修改以支持该功能的信息。使用Linux内核TLS的唯一可用示例可能是博客文章Filippo Valsorda ,在Linux 4.13和Go中使用内核TLS。,它在Linux 4.13内核发布后立即出现。而且,尽管它显示了使用技术的有效示例,但并没有使人们了解如何在实际项目中使用该技术。毕竟,很少有人为自己的项目编写WEB服务器,通常每个人都使用众所周知且经过时间考验的工具。

OpenSSL支持


OpenSSL技术的首次讨论出现在2017年夏天,Linux 4.13内核(PR 3631发布之前不久,但是讨论过程非常非常缓慢,最初的真正评论出现在10月(4.13内核发布之后),实际上是工作版本在2018年2月开始讨论。在完成所有更正之时,关闭了在OpenSSL 1.1.1中添加新功能的窗口,并且对内核TLS的支持已移至下一个版本。从那时起,添加了内核TLS RX支持,并且SSL_sendfile()是对相应syscall的调用,仅对TLS协议中的可能情况进行了少量处理。但是现在到2020年,OpenSSL 3.0尚未问世,绝大多数浏览器都支持TLSv1.3,而更具抵抗力的AES256-GCM积极取代了AES128-GCM密码。因此,我自由了,发送了一个Pull请求以支持新密码和TLSv1.3,希望他们在新版本的库之前接受它。

WEB服务器中的支持


但是在TLS库中仅支持内核TLS是不够的。有关该技术的报道说,使用send而不将数据复制到用户空间可以实现最大效率-使用sendfile()系统调用。服务器应用程序应该能够区分可以在带TLS的套接字上使用sendfile()以及何时需要“以旧方式读取” read()/ SSL_write()的情况。 2019年4月,在向Nginx添加功能方面取得了一些进展,但主要代码未接受任何更改。开发人员的立场是,尚未批准OpenSSL中用于这些功能的API,并且补丁中建议的实际代码似乎不足以移植到不同平台。老实说,该代码不仅看起来不太漂亮,而且还包含一些错误,这些错误会阻止在没有其他更正的情况下构建Nginx。我根本找不到其他Web服务器中的Kernel TLS支持(也许有人看到了-在评论中告诉我)。

怎么办?


当社区在等待OpenSSL 3.0的发布时,为了开始使用稳定的API在Nginx中开发对内核TLS的支持,我选择了另一种方法。在我舒适的 GitHub 角落,我做了两件事:

  1. 我创建了一个OpenSSL 分支,并将与内核TLS相关的所有内容都反向移植到了OpenSSL 1.1.1(OpenSSL_1_1_1-ktls分支)的稳定版本中。特别是为了能够在库的其余部分稳定运行的情况下检查功能。随着稳定版本的推出,我会尝试重新设置基础,以使分叉保持最新状态。
  2. 我创建了Nginx的一个分支,在其中添加了(基于Mellanox的补丁)支持,以便在确实可行且具有必要的SSL套接字检查的条件下调用SSL_sendfile(),并具有通过配置变量启用/禁用功能的能力。除了此功能外,在我的fork中还提供了几个补丁,这些补丁可以稍微优化Nginx的工作并修复一些错误(master-feature分支)。为了使fork保持最新状态,我尝试尽可能地基于Nginx主仓库的master分支进行基准调整。

我邀请所有人参加测试。可以在GitHub上的Issues中抛出对代码的注释和更正。要使用此OpenSSL和随附的内核TLS支持构建此Nginx,请向configure脚本添加参数:

./configure --with-openssl=<OpenSSL-fork-dir> --with-openssl-opt="enable-ktls"

目前,我没有机会在严重负载下测试此Nginx + OpenSSL捆绑包,以确认从注释到Nginx补丁的性能,因此,如果突然有人可以测量高文件上传速度下CPU负载的差异,那么获取图形并添加图形将很棒将它们整理成文章,以直观地了解效果。

All Articles