NGINX Full Version

隆重推出 NGINX Plus R29

很高兴宣布推出 NGINX Plus Release 29 (R29) 版本。NGINX Plus 基于 NGINX 开源版构建而成,是唯一一款将软件 Web 服务器、负载均衡器、反向代理、内容缓存和 API 网关集于一身的多合一产品。
NGINX Plus R29 的新增特性包括:

重要行为变更

:如果您不是从 NGINX Plus R28 升级至 NGINX Plus R29,请务必查看之前的公告博客中的“重要行为变更”部分,了解当前版本和最新版本之间所有版本的嬗变过程。

软件包代码库的变更

随着 NGINX Plus R29 的发布,旧软件包代码库 plus-pkgs.nginx.com 将立即停用。该代码库自 NGINX Plus R25 以来一直没有更新,强烈建议您使用 NGINX Plus R24 中引入pkgs.nginx.com 软件包代码库。

平台支持的变更

全新操作系统支持:

不再支持的旧版操作系统:

以下旧版操作系统已弃用并计划在 NGINX Plus R30 中移除:

根据 ModSecurity 生命周期终止公告做出调整

根据 ModSecurity 生命周期终止公告,NGINX Plus R29 不再支持 ModSecurity 软件包。作为使用 ModSecurity 软件包的 NGINX Plus 客户,您很快便可选择参加 ModSecurity 和 NGINX App Protect 之间的折价换购计划。有关该计划的详细信息将很快公布,您可以联系您的 F5 客户代表,了解更多信息。

新增特性详情

支持 MQTT 协议

MQTT(消息队列遥测传输)是一种常用的轻量级发布-订阅消息协议,非常适合通过互联网连接物联网设备和应用(客户端)。它支持客户端围绕特定主题发布消息并订阅其他主题。订阅的客户端会收到围绕该主题发布的所有消息,从而在许多设备和服务之间实现高效的、支持容错的数据交换。

MQTT 架构的核心是 Broker。Broker 是一台服务器,负责跟踪客户端及其订阅的任何主题、处理消息,并将这些消息路由到相应系统。NGINX Plus R29 支持 MQTT 3.1.1MQTT 5.0。它充当了客户端和 Broker 之间的代理,可简化系统架构,卸载任务,并降低成本。

初始 MQTT 特性集支持:

MQTT 协议定义了几种消息类型,包括 CONNECT、PUBLISH 和 SUBSCRIBE。NGINX Plus R29 能够主动解析并重写 MQTT CONNECT 消息的部分内容,从而构建以前只能通过自定义脚本创建的配置场景。

MQTT 消息解析和重写必须在 NGINX 配置文件的 Stream 上下文中进行定义,并可通过 ngx_stream_mqtt_preread_module
ngx_stream_mqtt_filter_module 模块实现。

MQTT 示例

通过修改 MQTT 设备发送的默认客户端标识符,NGINX 可以隐藏敏感信息,例如设备的序列号。在第一个示例中,标识符被重写为设备的 IP 地址。

注:不建议在生产环境中使用设备的 IP 地址作为 MQTT 客户端标识符。

stream {
      mqtt on;
    server {         listen 1883;         proxy_pass 10.0.0.8:1883;         mqtt_rewrite_buffer_size 16k;         mqtt_set_connect clientid '$remote_addr';     } }

鉴于 MQTT 客户端的短连接行为,因此您不能仅依靠设备的主机名或 IP 地址来与负载均衡的 Broker 建立会话保持。在本例中,设备的 MQTT 客户端标识符作为哈希键,用于持久连接到负载均衡集群中的各个 MQTT broker:

stream {
      mqtt_preread on;
    upstream brokers{         zone tcp_mem 64k;         hash $mqtt_preread_clientid consistent;
        server 10.0.0.7:1883; # mqtt broker 1         server 10.0.0.8:1883; # mqtt broker 2         server 10.0.0.9:1883; # mqtt broker 3     }
    server {         listen 1883;         proxy_pass brokers;         proxy_connect_timeout 1s;     } }

后续步骤

NGINX Plus 中 MQTT 的后续开发可能包括对其他 MQTT 消息类型进行解析,并能够更深入地解析 CONNECT 消息以启用以下功能:

欢迎您就所看重的特性给我们反馈,请发送邮件至 contactme_nginxapac@f5.com 告诉我们您的想法。

支持 SAML 身份验证和授权

SAML(Security Assertion Markup Language,安全防护声明标记语言)是一套开放的联合标准,允许身份验证供应商 (IdP) 对访问资源的用户进行身份验证(确保最终用户身份的真实性),并将这些身份验证信息及用户对该资源的访问权限传递给服务提供商 (SP) 进行授权。

SAML 作为一套成熟的身份数据安全交换标准,已被广泛用于在 IdP 和 SP 之间交换身份验证和授权信息。

企业和政府机构选择采用 SAML 的主要原因如下:

 
SAML 还提供了诸多优势:

SAML 的当前参考实现使用 SAML 2.0,并采用 NGINX JavaScript (njs) 框架构建而成。在此实现中,NGINX Plus 充当 SAML SP,与 SAML IdP 共同完成 SSO 设置。当前实现还依赖于键值存储,后者是 NGINX Plus 中的一项特性,因此除非作进一步修改,否则该实现不适合 NGINX 开源版。

NGINX Plus 中的 SAML 支持在 GitHub 上提供参考实现。代码库提供了一个示例配置,其中包含有关特定用例的安装、配置及微调说明。

原生 OpenTelemetry

OpenTelemetry (OTel) 是一种可用于监控、跟踪、排除故障及优化应用的技术和标准。其工作原理是从已部署应用堆栈中的代理、应用或其他服务等各种来源收集遥测数据。

作为协议感知型反向代理和负载均衡器,NGINX 是启动遥测调用来跟踪应用请求和响应的理想位置。虽然第三方 OTel 模块已经使用了很长时间,但现在我们很高兴地宣布 NGINX Plus 的一个新动态模块将提供对 OTel 的原生支持。

这个新模块 ngx_otel_module 可使用 nginx-plus-module-otel 包进行安装,相比第三方模块做了一些重要改进,包括:

有关 OTel 动态模块的更多详细信息,请参阅 NGINX 文档

OTel 链路追踪示例

以下是 NGINX 直接服务的一个应用的基本 OTel 链路追踪示例:

load_module modules/ngx_otel_module.so;
events {}
http {     otel_exporter {         endpoint localhost:4317;     }  
    server {         listen 127.0.0.1:8080;         
        otel_trace on;         otel_span_name app1;     } }

在下面的示例中,我们仅在对父 span 进行采样时才会从传入请求继承链路追踪上下文并记录 span。我们还将链路追踪上下文和采样决策传播到上游服务器。

load_module modules/ngx_otel_module.so;
http {     server {         location / {             otel_trace $otel_parent_sampled;             otel_trace_context propagate;             proxy_pass http://backend;         }     } }

在此基于比率的示例中,根据一定比例的流量配置链路追踪(本例中为 10%):

http {
      # 跟踪 10% 的请求
      split_clients "$otel_trace_id" $ratio_sampler {
          10%     on;
          *       off;
      }
    # 或者我们可以跟踪 10% 的用户会话
    split_clients "$cookie_sessionid" $session_sampler {         10%     on;         *       off;     }
    server {         location / {             otel_trace $ratio_sampler;             otel_trace_context inject;
            proxy_pass http://backend;         }     } }

在此 API 控制的示例中,通过 /api 端点控制键值存储来启用链路追踪:

http {
      keyval "otel.trace" $trace_switch zone=name;
    server {         location / {             otel_trace $trace_switch;             otel_trace_context inject;             proxy_pass http://backend;         }
        location /api {             api write=on;         }      } }

实验性 QUIC+HTTP/3 包

发布 NGINX 开源版的预览版二进制包后,我们很高兴地宣布推出 NGINX Plus R29 的实验性 QUIC 包。它支持使用 NGINX Plus 测试并评估 HTTP/3。

借助一个新的底层协议堆栈,HTTP/3 将 UDP 和 QUIC 引入传输层。QUIC 是一种加密传输协议,旨在通过提供连接复用和解决队头阻塞等问题来改进 TCP。它重新实现并增强了 HTTP/1.1 和 HTTP/2 的一些 TCP 功能,包括连接建立、拥塞控制及可靠交付。QUIC 还将 TLS 作为一个整体构件,而不像 HTTP/1.1 和 HTTP/2 那样将 TLS 作为一个单独的层。这意味着 HTTP/3 消息本身就很安全,因为它们默认通过加密连接发送请求。

通常,对于安全通信和加密功能,NGINX Plus 依靠 OpenSSL,以利用操作系统自带的 SSL/TLS 库。但由于截至本文撰写时,OpenSSL 不支持 QUIC 的 TLS 接口,因此需要第三方库来提供 HTTP/3 所需的 TLS 功能。

为了解决这一问题,我们为 QUIC 开发了一个 OpenSSL 兼容层,这样就无需构建和交付第三方 TLS 库,例如 Quictls、BoringSSL 和 LibreSSL。这有助于管理 NGINX 中的端到端 QUIC+HTTP/3 体验,既无需自定义 TLS 实现,也不必依赖第三方库的进度表和路线图。

:OpenSSL 兼容层包含在实验性 NGINX Plus QUIC+HTTP/3 包中,需要使用 OpenSSL 1.1.1 或更高版本来提供 TLSv1.3(这是 QUIC 协议所要求的)。它尚未实现 0-RTT。

QUIC+HTTP/3 示例配置

下面我们来看看 NGINX Plus 中 QUIC+HTTP/3 的示例配置:

http {
      log_format quic '$remote_addr - $remote_user [$time_local]'
      '"$request" $status $body_bytes_sent '
      '"$http_referer" "$http_user_agent" "$http3"';
    access_log logs/access.log quic;
    server {         # 为了提高兼容性,建议         # 对 quic 和 https 使用同一端口         listen 8443 quic reuseport;         listen 8443 ssl;
        ssl_certificate     certs/example.com.crt;         ssl_certificate_key certs/example.com.key;
        location / {             # 需要浏览器将其定向到 quic 端口             add_header Alt-Svc 'h3=":8443"; ma=86400';         }     } }

类似于我们的 HTTP/2 的实现,当 NGINX Plus 作为代理时,QUIC+HTTP/3 连接在客户端建立,并在连接到后端和上游服务时转换为 HTTP/1.1。

实验性 NGINX Plus QUIC+HTTP/3 包可以从单独的代码库中获取,并可通过现有 NGINX Plus 证书和密钥访问。实验性 QUIC 包的安装类似于标准 NGINX Plus 安装。请确保使用 QUIC 代码库,如安装步骤所示。

您可以参阅“针对 QUIC+HTTP/3 的 NGINX 配置”一节,详细了解如何针对 QUIC+HTTP/3 配置 NGINX。如欲了解有关所有新指令和变量的信息,请参阅 nginx-quic README 的“配置”部分。

后续步骤

近期,我们计划将 QUIC+HTTP/3 代码合并到 NGINX 主线分支。然后,支持 QUIC+HTTP/3 的最新版 NGINX 主线将被合并到下一 NGINX Plus 版本中。预计今年晚些时候将正式发布 NGINX Plus 提供 QUIC+HTTP/3 支持的公告。

NGINX Plus R29 的其他增强功能

OpenID Connect 变更

OpenID Connect (OIDC) 支持是在 NGINX Plus R15 中引入的,然后在后续版本中得到了显著增强。NGINX Plus R29 将继续增强 OIDC,并增添了以下特性。

支持访问令牌

访问令牌用于基于令牌的身份验证,以允许 OIDC 客户端代表用户访问受保护的资源。NGINX Plus 在用户成功进行身份验证并授权访问后会收到一个访问令牌,然后将其存储到键值存储中。对于发送到下游应用的每个请求,NGINX Plus 可通过 HTTP Authorization 请求头将该令牌作为的 Bearer 令牌进行传递。

:NGINX Plus 不会验证每个请求的访问令牌的有效性(与 ID 令牌一样),也无法知道访问令牌是否已经过期。如果访问令牌的生命周期小于 ID 令牌的生命周期,那么您必须使用 proxy_intercept_errors on 指令。这将拦截并重定向对 NGINX 的 401 Unauthorized 响应,并更新访问令牌。

有关 NGINX Plus 支持 OpenID Connect 和 JSON Web 令牌 (JWT) 验证的更多信息,请参阅《借助 OpenID Connect 和 NGINX Plus 对访问当前应用的用户进行身份验证》。

在 OIDC 身份验证端点中添加参数

一些身份验证供应商(例如 Keycloak)允许向身份验证请求添加额外的查询字符串参数,以启用附加功能。 例如,Keycloak 允许通过向身份验证请求添加 kc_idp_hint 参数来指定默认 IdP。借助此增强特性,用户可为 OIDC 授权端点指定其他参数。

Prometheus-njs 模块中的扩展 SSL 计数器

在 NGINX Plus R28 中,我们为面向客户端和服务器端连接的 HTTP 和 Stream 模块中的握手错误和证书验证失败提供了额外的 SSL 计数器支持。我们的 Prometheus-njs 模块不仅能够将 NGINX Plus 指标转换为 Prometheus 数据格式,而且现在还支持这些计数器。

新的 internal_redirect 指令

新的 internal_redirect 指令和模块允许在检查 request 处理限制、connection 处理限制及 access 限制后进行内部重定向。

以下是 internal_redirect 配置示例:

http {
      limit_req_zone $jwt_claim_sub zone=jwt_sub:10m rate=1r/s; 
    server {         location / {             auth_jwt "realm";             auth_jwt_key_file key.jwk;
            internal_redirect @rate_limited;         }
        location @rate_limited {             internal;             limit_req zone=jwt_sub burst=10;
         proxy_pass http://backend;         }     } }

在上例中,JWT 身份验证在 location 块执行,如果令牌有效,则请求将传递给内部内容处理器 @rate_limited,其中根据 sub 声明值应用请求速率限制。这在 JWT 中进行,直至请求传递到上游服务。

此特定配置能够防止拒绝服务 (DoS) 攻击,即攻击者发送大量包含可读 JWT 的请求,以特定用户作为 sub 字段。大量请求不会通过身份验证,但将计入速率限制。通过在将请求传递给内容处理器之前对 JWT 进行身份验证,您可以确保仅有效请求才计入速率限制。

从 NGINX 开源版继承的变更

NGINX Plus R29 基于 NGINX 开源版 1.23.4,继承了自 NGINX Plus R28 发布以来(NGINX 1.23.3 到 1.23.4)的功能变更和漏洞修复。

变更

特性

漏洞修复

变通方案

有关从这些版本继承的新特性、变更、漏洞修复及变通方案的完整列表,请参见变更文件。

NGINX JavaScript 模块的变更

NGINX Plus R29 包含从 NGINX JavaScript (njs) 模块版本 0.7.9 到 0.7.12 的变更。njs 中添加了多个卓越特性,包括:

有关 njs 版本 0.7.9 到 0.7.12 的所有特性、变更及漏洞修复的完整列表,请参阅 njs 变更日志

扩展的 Fetch API 支持

在 Fetch API 中添加了 Headers()Request()Response() 构造函数及其他增强函数:

async function makeRequest(uri, headers) {
      let h = new Headers(headers);
      h.delete("bar");
      h.append("foo", "xxx");
      let r = new Request(uri, {headers: h});
      return await ngx.fetch(r);
  }

扩展的 Web Crypto API

Web Crypto API 已扩展为支持 JSON Web Key (JWK) 格式,importKey() 现在接受 JWK 格式的密钥作为输入:

async function importSigningJWK(jwk) {
     return await crypto.subtle.importKey('jwk', jwk,
                                          {name: "RSASSA-PKCS1-v1_5"},
                                          true, ['sign']);
  }

njs 0.7.10 还增加了 generateKey()exportKey() 方法。generateKey() 方法允许您为对称算法生成新密钥,或者为公钥算法生成密钥对。exportKey() 方法将 CryptoKey 对象作为输入,并以外部可移植格式返回密钥。它支持 JWK 格式,可将密钥作为 JSON 对象导出。

更多详情,请参考 Web Crypto API

XML 文档支持

njs 0.7.10 中添加了 XML 模块,可为处理 XML 文档提供原生支持。

XML 文档解析

您现在可以解析 XML 文档的字符串或缓冲区,然后返回一个 XMLDoc 代表已解析 XML 文档的包装器对象:

const xml = require("xml");
  let data = `<note><to b="bar" a= "foo">Tove</to><from>Jani</from></note>`;
  let doc = xml.parse(data);
   
console.log(doc.note.to.$text) /* 'Tove' */ console.log(doc.note.to.$attr$b) /* 'bar' */ console.log(doc.note.$tags[1].$text) /* 'Jani' */

用于修改 XML 文档的 XMLNode API

在 njs 0.7.11 中添加了 XMLNode API,用于修改 XML 文档:

Const xml = require("xml");
  let data = `<note><to b="bar" a="foo">Tove</to><from>Jani</from></note>`;
  let doc = xml.parse(data);
   
doc.$root.to.$attr$b = 'bar2'; doc.$root.to.setAttribute('c', 'baz'); delete doc.$root.to.$attr$a;  
console.log(xml.serializeToString(doc.$root.to)) /* '<to b="bar2" c="baz">Tove</to>' */  
doc.$root.to.removeAllAttributes(); doc.$root.from.$text = 'Jani2';  
console.log(xml.serializeToString(doc)) /* '<note><to>Tove</to><from>Jani2</from></note>' */  
doc.$root.to.$tags = [xml.parse(`<a/>`), xml.parse(`<b/>`)]; doc.$root.to.addChild(xml.parse(`<a/>`));
console.log(xml.serializeToString(doc.$root.to)) /* '<to><a></a><b></b><a></a></to>' */  
doc.$root.to.removeChildren('a');  
console.log(xml.serializeToString(doc.$root.to)) /* '<to><b></b></to>' */

如欲了解有关所有 XML 相关增强特性的更多详细信息,请参阅 XML 文档

Zlib 模块压缩支持

zlib 模块已添加到 njs 0.7.12 中,可使用 deflate 和 inflate 算法提供压缩功能。

Const zlib = require('zlib');
  zlib.deflateRawSync('αβγ').toString('base64')
  /* "O7fx3KzzmwE=" */
   
zlib.inflateRawSync(Buffer.from('O7fx3KzzmwE=', 'base64')).toString() /* "αβγ" */

如欲了解有关 zlib 的更多详细信息,请参阅 zlib 文件

升级或试用 NGINX Plus

如果您是 NGINX Plus 用户,我们强烈建议您尽快升级到 NGINX Plus R29。除了上述所有新特性以外,您还将获得更多修复和改进。升级到最新版本有助于 NGINX 团队在您需要时为您快速提供支持。

如果您还不是 NGINX Plus 用户,我们建议您立即申请试用 —它具备强大的安全防护,可充当负载均衡器、API 网关或者具备增强的监控和管理 API 的 Web 服务器,并且 NGINX 团队将提供支持服务。请立即下载 30 天免费试用版