NGINX Plus R18正式发布

NGINX | 2019年4月09日


我们很高兴地宣布,NGINX Plus Release 18(R18)现已发布。NGINX Plus是一款集负载均衡器、内容缓存、Web服务器和API网关于一体的解决方案。NGINX Plus基于NGINX Open Source构建,提供专属增强功能和广受认可的支持服务。R18简化了DevOps配置工作流,并增强了应用在规模化运行时的安全性和可靠性。

目前,超过87%的网站使用SSL/TLS加密互联网通信,而3年前这一比例仅为66%。端到端加密现已成为网站和应用的默认部署模式。随着SSL/TLS证书数量激增,一些公司需要在生产环境中管理数以万计的证书,因此需要采用更灵活的证书部署和配置方式。

此版本新增了对动态证书加载的支持。如果有数千个证书,在配置中逐一手动定义并从磁盘加载并不具备可扩展性。这一过程不仅繁琐,还会导致配置文件过于庞大,NGINX Plus启动速度慢到难以接受。借助NGINX Plus R18,现在无需在配置中逐一列出SSL/TLS证书,即可按需加载。为进一步简化自动化部署,还可以通过NGINX Plus API配置证书,甚至无需将证书存储在磁盘上。

NGINX Plus R18的其他新功能包括:

  • OpenID Connect增强功能:我们持续改进所支持的OpenID Connect参考实现,该实现最初随NGINX Plus R15发布。此版本新增了对不透明会话令牌、刷新令牌和注销URL的支持。
  • 虚拟服务器的端口范围:现在可将NGINX Plus虚拟服务器配置为侦听一系列端口,例如80‑90。这使NGINX Plus能够支持更多需要预留端口范围的应用,例如被动FTP。
  • 配置中的键值定义:NGINX Plus键值存储可为多种使用场景提供解决方案,包括动态将IP地址加入拒绝列表和动态缓解DDoS攻击。现在,可以直接在NGINX Plus配置中使用变量创建键值对,从而支持更多使用场景。
  • 更灵活的主动健康检查 ,NGINX Plus的主动健康检查是监控后端系统运行状况的强大工具。借助NGINX Plus R18,现在可以测试任意NGINX变量的值,并自动关闭与故障服务器之间的现有TCP连接。

本次版本还包括简化的集群环境配置,以及新增和更新的动态模块(包括Brotli)。NGINX Plus生态系统更新包括使用NGINX JavaScript模块实现模块化代码组织,以及通过Helm直接安装适用于Kubernetes的官方NGINX Ingress Controller。

重要行为变更

  • 已废弃的API:NGINX Plus R13(2017年8月)引入了全新的NGINX Plus API,用于指标收集和上游组的动态重新配置,取代了此前实现这些功能的Status API和Upstream Conf API。正如当时所宣布的,已弃用的API在相当长一段时间内仍可用并受到支持,直至NGINX Plus R16。如果配置中包含status和/或upstream_conf指令,则在升级到R18时必须将其替换为api指令。如需获取迁移到新版NGINX Plus API的建议和帮助,请参阅博客中的迁移指南,或联系我们的支持团队。
  • 更新后的listen指令:以前,当listen指令指定的主机名解析为多个IP地址时,只使用第一个IP地址。现在,会为返回的每个IP地址创建一个侦听套接字。
  • NGINX JavaScript模块(njs)变更:已从已弃用的 req.response对象已从NGINX JavaScript模块中移除。使用function(req,res)语法声明且引用res对象属性的函数会产生运行时错误,返回HTTP状态码500,并在错误日志中生成相应条目:
YYYY/MM/DD hh:mm:ss [error] 34#34: js exception: TypeError: cannot get property "return" of undefined
  • 由于JavaScript代码在运行时解释执行,nginx -t语法验证命令无法检测无效对象和属性。升级到NGINX Plus R18之前,必须仔细检查JavaScript代码并移除此类对象。此外,当给定属性没有值时,表示NGINX状态的JavaScript对象(例如r.headersIn)现在会返回undefined,而不是空字符串。这一变化意味着NGINX专用JavaScript对象现在与内置JavaScript对象的行为一致。
  • 已移除或即将移除的旧版操作系统:
    • Amazon Linux 2017.09已不再受支持;目前支持的最早版本为2018.03
    • 不再支持CentOS/Oracle Linux/Red Hat Enterprise Linux 7.3;目前支持的最低版本为7.4
    • Debian 8.0 将在 NGINX Plus R19 中移除
    • Ubuntu 14.04 将在 NGINX Plus R19 中移除

新功能详解

动态加载SSL/TLS证书

在以前的NGINX Plus版本中,管理安全站点和应用的SSL/TLS证书通常需要为每个主机名分别创建一个server块,并以磁盘文件的形式静态指定证书及其关联的私钥。(为便于阅读,下文将使用证书统称配对的证书和密钥。)这些证书随后会在NGINX Plus启动时加载。从NGINX Plus R18开始,证书可以动态加载,还可选择存储在NGINX Plus的内存键值存储中,而不是存储在磁盘上。

动态加载证书主要有两种用例:

在这两种情况下,NGINX Plus都可以根据TLS握手期间服务器名称指示(SNI)提供的主机名动态加载证书。这样,NGINX Plus便可通过单个服务器配置托管多个安全网站,并按需为每个传入请求选择适当的证书。

从磁盘延迟加载SSL/TLS证书

采用“延迟加载”时,只有在请求到达并指定相应主机名后,SSL/TLS证书才会加载到内存中。这样既能简化配置(无需列出每个主机名对应的证书),又能减少主机的资源占用。如果证书数量庞大(数千个甚至更多),从磁盘读取所有证书并将其加载到内存中可能需要数秒。此外,重新加载NGINX配置时会占用大量内存,因为新的一组工作进程会将一份新的证书副本加载到内存中,而此前一组工作进程加载的证书仍在内存中。在旧配置下建立的最后一个连接结束且此前的工作进程终止之前,原有证书会一直保留在内存中。如果配置更新频繁且客户端连接持续时间较长,内存中可能同时存在多份证书副本,进而可能导致内存耗尽。

从磁盘延迟加载证书非常适合证书数量庞大和/或需要频繁重新加载配置的部署场景。例如,SaaS公司通常会为每位客户分配单独的子域。新客户的接入过程较为复杂,因为需要为每位客户创建新的虚拟服务器,然后将新配置和客户证书复制到每个NGINX Plus实例。延迟加载无需更改配置,只需在每个实例上部署证书即可。

为支持延迟加载,ssl_certificate和ssl_certificate_key指令现在接受变量参数。该变量必须在SNI处理期间可用,而SNI处理发生在读取请求行和标头之前。最常用的变量是$ssl_server_name,用于保存NGINX Plus在SNI处理期间提取的主机名。每个客户端会话开始时,系统会在TLS握手期间从磁盘读取证书和密钥,并通过文件系统缓存将其缓存在内存中,从而进一步降低内存使用量。

安全站点配置可简化为:

正在加载代码示例…

同一套server配置可用于任意数量的安全站点。这样做有两个好处:

  1. 无需再为每个主机名单独设置server块,从而大幅精简配置,使其更易于阅读和管理。
  2. 无需在每次添加新主机名时重新加载配置。即使确实需要重新加载,速度也会快得多,因为NGINX Plus不会加载所有证书。

请注意,由于从磁盘检索证书需要调用文件系统,延迟加载会使TLS握手耗时增加20%–30%,具体取决于环境。不过,额外的延迟仅影响握手;TLS会话建立后,请求处理耗时与平时相同。

内存中的SSL/TLS证书存储

现在,除了存储在磁盘文件中,还可以将SSL/TLS证书数据存储在内存中的NGINX Plus 键值存储中。当ssl_certificate或ssl_certificate_key指令的参数以data:前缀开头时,NGINX Plus会将该参数解释为原始PEM数据(以变量形式提供,该变量用于标识键值存储中实际存放数据的条目)。

将数据存储在键值存储区而非磁盘上还有一个好处:部署映像和备份不再包含私钥副本,攻击者可能利用私钥副本解密服务器收发的所有流量。对于部署流水线高度自动化的公司,可以使用NGINX Plus API以编程方式将证书插入键值存储区,从而获得更大的灵活性。此外,对于将应用迁移到公有云环境且没有实体硬件安全模块(HSM)来保护私钥的公司,不在磁盘上存储私钥还可增强安全性。

以下是从键值存储加载证书的配置示例:

正在加载代码示例…

使用NGINX Plus API将证书和私钥上传到键值存储的一种方法是运行以下curl命令(此处仅显示密钥数据开头的一小部分)。如果使用curl命令,请记得复制一份PEM数据,并将每个换行符替换为\n;否则,JSON有效负载中的换行符会被移除。

$ curl -d '{"www.example.com":"-----BEGIN RSA PRIVATE KEY-----\n..."}' http://localhost:8080/api/4/http/keyvals/ssl_key

使用键值存储来管理证书非常适合NGINX Plus的集群部署,因为只需上传一次证书,即可自动分发到整个集群。为保护证书数据本身,请使用zone_sync_ssl指令对集群成员之间的连接进行TLS加密。键值存储也非常适合管理短期证书,或自动与证书颁发机构集成,例如Let’s Encrypt和Hashicorp Vault。

与从磁盘延迟加载一样,每次TLS握手时都会从键值存储加载证书,因此会影响性能。为提高TLS握手速度,请使用ssl_certificate和ssl_certificate_key指令,并将参数硬编码为磁盘上的文件路径。此外,ECC证书的速度比RSA证书更快。

请注意,与磁盘存储相比,键值存储会增加攻击者获取私钥文件的难度,但拥有NGINX Plus主机shell访问权限的攻击者仍有可能访问已加载到内存中的密钥。键值存储对私钥的保护程度不及硬件安全模块(HSM);要让NGINX Plus从HSM获取密钥,请在engine:engine-name:key-id参数中使用ssl_certificate_key指令。

OpenID Connect 增强功能

NGINX Plus通过我们的参考实现为后端应用提供OpenID Connect身份验证和单点登录支持。现在,可以在JavaScript模块中使用变量直接修改键值存储,因此该实现得到了简化和增强(见下文)。

OpenID Connect参考实现现在以浏览器Cookie的形式向客户端颁发不透明会话令牌。不透明令牌不包含用户的任何个人身份信息,因此客户端不会存储敏感信息。NGINX Plus将实际的ID令牌存储在键值存储中,并用该令牌替换客户端提供的不透明令牌。系统会对每个请求执行JWT验证,以拒绝已过期或无效的令牌。

OpenID Connect参考实现现在还支持刷新令牌,无需用户交互即可无缝刷新已过期的ID令牌。NGINX Plus将授权服务器发送的刷新令牌存储在键值存储中,并将其与不透明会话令牌关联。ID令牌过期时,NGINX Plus会将刷新令牌发回授权服务器。如果会话仍然有效,授权服务器会签发新的ID令牌,并在键值存储中无缝更新该令牌。借助刷新令牌,可以使用短期有效的ID令牌,在不影响用户体验的情况下提升安全性。

OpenID Connect参考实现现在提供注销URL。已登录用户访问/logout URI后,其ID令牌和刷新令牌将从键值存储中删除,之后发出请求时必须重新进行身份验证。

虚拟服务器的端口范围

A server block typically has one listen directive specifying the single port on which NGINX Plus listens; if multiple ports need to be configured, there’s an additional listen directive for each of them. With NGINX Plus R18, you can now also specify port ranges, for example 80‑90, when it is inconvenient to specify a large number of individual listen directives.

可为HTTP listen指令和TCP/UDP(Stream)listen指令指定端口范围。以下配置使NGINX Plus能够代理被动模式的FTP服务器,其数据端口从较大的TCP端口范围中选择。

正在加载代码示例…

此配置会设置一个虚拟服务器,通过连接传入时使用的同一端口,将连接代理到FTP服务器。

通过变量更新键值存储

启用键值存储后,NGINX Plus会根据输入键(通常是请求元数据的一部分)提供一个变量,用于表示其中存储的值。此前,只能使用NGINX Plus API在键值存储中创建、修改或删除值。从NGINX Plus R18开始,可以通过设置保存相应值的变量,直接在配置中更改键对应的值。

以下示例使用键值存储维护最近访问过该站点的客户端IP地址列表,以及这些客户端最后请求的URI。

正在加载代码示例…

对于每个客户端IP地址(set指令(第 7 行)都会为其赋值($last_uri)($remote_addr)。如果条目不存在,则创建新条目;否则修改该值,以反映当前请求的$uri。因此,调用NGINX Plus API即可获取当前的近期客户端及其请求URI列表:

$ curl http://localhost:8080/api/4/http/keyvals/recents{
  "10.19.245.68": "/blog/nginx-plus-r18-released/",
  "172.16.80.227": "/products/nginx/",
  "10.219.110.168": "/blog/nginx-unit-1-8-0-now-available"
}

借助NGINX JavaScript模块(njs)和Lua模块等脚本扩展,可以实现功能更强大的用例。任何使用njs的配置都可以访问所有变量,包括由键值存储支持的变量,例如r.variables.last_uri。

主动健康检查更加灵活

NGINX Plus的主动运行状况检查会定期测试后端系统,避免将流量定向到已知运行状况不佳的系统。NGINX Plus R18为这项重要功能新增了两项能力。

在运行状况检查中测试任意变量

为后端应用定义运行状况检查时,可以使用match块指定响应中多个方面的预期值,包括HTTP状态码以及响应标头和/或正文中的字符串。当响应包含所有预期值时,后端将被视为运行状况良好。

对于更复杂的检查,NGINX Plus R18现提供require指令,用于测试任意变量的值,包括标准NGINX变量和自行声明的变量。由于可以使用map块、正则表达式甚至脚本扩展来评估变量,因此可以更灵活地定义健康检查。

The require 指令位于 match 块内,用于指定一个或多个变量。所有变量的值都必须非零,测试才能通过。以下示例配置将健康的上游服务器定义为返回表明响应可缓存的标头,即值非零的 Expires 标头或 Cache-Control 标头。

正在加载代码示例…

以这种方式使用“map”块,是在NGINX Plus配置中加入OR逻辑的常用方法。“require”指令支持在健康检查中运用此方法,也可用于执行高级健康检查。还可以使用JavaScript模块(njs)分析每个上游服务器响应的其他属性(例如响应时间),从而定义高级健康检查。

健康检查失败时终止第 4 层连接

当NGINX Plus充当TCP/UDP应用的第4层(L4)负载均衡器时,会通过客户端与后端服务器之间建立的连接双向代理数据。主动健康检查是此类配置的重要组成部分,但默认情况下,只有当新客户端尝试建立连接时,系统才会考虑后端服务器的健康状态。如果后端服务器离线,已建立连接的客户端向该服务器发送数据时可能会遇到超时。

借助NGINX Plus R18中新增的proxy_session_drop指令,当从离线服务器接收或向其发送下一个数据包时,可以立即关闭连接。客户端将被强制重新连接,此时NGINX Plus会将其请求代理到运行正常的后端服务器。

启用此指令后,另外两种情况也会触发终止现有连接:主动健康检查失败,以及服务器因任何原因从上游组中移除。这包括通过DNS查询移除服务器的情况,其中后端服务器由具有多个IP地址的主机名定义,例如由服务注册中心提供的IP地址。

NGINX Plus R18 的其他增强功能

简化的集群配置

自NGINX Plus R15起,NGINX Plus便支持在整个集群范围内同步运行时状态。目前,区域同步模块支持在NGINX Plus实例的集群部署中共享以下状态数据:会话保持、速率限制和键值存储。

现在,单个zone_sync配置可用于集群中的所有实例。以前,必须明确配置每个成员的IP地址或主机名,因此每个实例的配置都略有不同。现在,可以为zone_sync服务器的address:port参数指定通配符值,使其侦听所有本地接口。该参数属于listen指令。在动态集群中部署NGINX Plus时,这项功能尤其有用,因为实例的IP地址要到部署时才能确定。

在每个实例上使用相同的配置,可大幅简化动态环境(例如使用自动扩缩容组或容器化集群的环境)中的部署。

新增和更新的动态模块

此版本新增或更新了以下动态模块:

  • 新增Brotli压缩模块:Brotli是一种通用无损数据压缩算法,采用LZ77算法的变体、霍夫曼编码和二阶上下文建模。
  • 新增OpenTracing模块,现在可以使用符合OpenTracing规范的请求对NGINX Plus进行插桩,以支持Datadog、Jaeger和Zipkin等多种分布式追踪服务。
  • 更新了Lua模块。Lua是用于NGINX Plus的脚本语言。该模块现已使用LuaJIT 2.1。

NGINX Plus生态系统更新

NGINX JavaScript Module 增强功能

NGINX JavaScript模块(njs)已更新至版本 0.3.0。其中较为显著的增强功能是支持JavaScript的import和export模块,可将JavaScript代码整理到多个具有特定功能的文件中。此前,所有JavaScript代码都必须存放在同一个文件中。

以下示例说明了如何使用JavaScript模块来组织和简化一个相对简单的用例所需的代码。这里使用JavaScript执行用于保护用户隐私的数据掩码,以便记录经过哈希处理(掩码)的客户端IP地址,而不是真实地址。日志中的同一掩码IP地址始终代表同一客户端,但无法还原为真实IP地址。

[编辑注:本节中的示例只是NGINX JavaScript模块众多用例之一。有关完整列表,请参阅《NGINX JavaScript模块用例》。

代码已更新为使用 js_import指令,该指令在js_includeNGINX Plus R23及更高版本中取代了NGINX JavaScript模块指令。有关详细信息,请参阅的参考文档,其中的“配置示例”部分展示了NGINX配置文件和JavaScript文件的正确语法。

在NGINX Plus R22及更高版本中,除了JavaScript import 和 export 模块外,还可以使用njs js_import 指令,将JavaScript代码组织到多个具有特定功能的文件中。]

我们将IP地址掩码所需的函数放入一个仅导出单个函数的JavaScript模块中,该函数为maskIp()。导出的函数依赖仅在模块内可用的私有函数,其他JavaScript代码无法调用这些私有函数。

正在加载代码示例…

现在可以将此模块导入主JavaScript文件(main.js),并引用导出的函数。

正在加载代码示例…

因此,main.js非常简单,仅包含NGINX配置所引用的函数。import语句用于指定模块文件的相对路径或绝对路径。使用相对路径时,可以通过新的js_path指令指定其他搜索路径。

正在加载代码示例…

这些新功能显著提升了代码的可读性和可维护性,尤其适用于使用大量njs指令和/或包含大量JavaScript代码的情况。现在,各团队可以分别维护自己的JavaScript代码,无需再将其复杂地合并到主JavaScript文件中。

使用Helm直接安装NGINX Ingress Controller for Kubernetes

现在可以直接从我们的新Helm仓库安装NGINX Ingress Controller for Kubernetes,无需下载Helm Chart源文件(但仍支持这种安装方式)。有关详细信息,请参阅GitHub仓库。

重要错误修复

UDP应用的带宽限制

The proxy_upload_rate 和 proxy_download_rate 指令现在可正确用于UDP数据报。

结合运行状况检查使用PROXY Protocol TLV会导致NGINX崩溃

此前,如果在引用了health_check指令的location中使用$proxy_protocol_tlv_0xEA变量(例如在AWS PrivateLink环境中),NGINX Plus可能会崩溃。

最短时间负载均衡忽略了响应最慢的上游服务器

以前,如果某个上游服务器长时间响应过慢,其指定时间指标值与其他上游服务器相比会非常高,因此可能永远不会再被选中。现在,随着新测量值使移动平均值逐渐降低,之前响应缓慢的上游服务器最终会重新加入负载均衡器的选择流程。

这适用于将上游响应时间用作选择指标的负载均衡算法,具体包括least_time,以及带有least_time参数的random算法。

升级或试用 NGINX Plus

如果您正在运行NGINX Plus,我们强烈建议尽快升级到NGINX Plus R18。升级后还可获得多项其他修复和改进,并有助于NGINX, Inc.在您需要提交支持工单时提供帮助。

在继续升级之前,请仔细查看本博文中介绍的新功能和行为变更。

如果您尚未试用过NGINX Plus,不妨亲自体验一下。它可用于安全防护、负载均衡和API网关,也可作为获得全面支持的Web服务器,并提供增强的监控和管理API。立即开始30天免费试用,亲自了解NGINX Plus如何帮助您交付应用并实现扩展。


分享
标签: SSL/TLS

关于作者

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。