NGINX.COM
Web Server Load Balancing with NGINX Plus

NGINX Plus Release 26 (R26)の提供を開始することをお知らせします。NGINX Plusは、NGINXオープンソースをベースにした、唯一のオールインワン・ソフトウェアWebサーバー、ロードバランサー、リバースプロキシ、コンテンツキャッシュ、およびAPIゲートウェイです。

NGINX Plus R26の新機能は以下の通りです。

  • JSON KeyキャッシングによるJWT検証の高速化 – 過去数回のリリースに渡り実施した一連のJSON Web Tokens(JWT)のサポートに関する機能の拡張を継続し、JSON Web Key Sets(JWKS)のインメモリキャッシングによりJWT検証のオーバーヘッドを大幅に削減します。
  • TLSハンドシェイクの強化 – NGINX Plusは、クライアントがALPNを介して確立するセッションのプロトコルを指定する際に、NGINXの設定内のコンテキストに一致しない通信プロトコルの場合(例えば、http{}コンテキストでVirtual Serverに対しIMAPを要求)、TLSハンドシェイクを拒否します。
  • NGINX JavaScriptモジュールの機能強化 – async, await, Promise Objectを利用した非同期処理の関数に対応しました。これにより暗号操作(乱数生成やCookieの暗号化等)に用いるWebCrypto APIの機能を追加しました。

今回のリリースでは、IBM System Z (s390x) アーキテクチャーのサポート、TCP コネクションの各方向を個別に閉じる機能、Perl Compatible Regular Expression (PCRE) ライブラリーのバージョン 2 のサポートが含まれています。

重要な動作の変化

NGINX JavaScriptモジュールでjs_includeをサポート終了

NGINX Plus R23のリリース時に発表されたように、NGINX JavaScriptモジュールのバージョン0.4.0では、js_includeディレクティブに代わってjs_importディレクティブが使用されるようになりました。js_includeディレクティブはその時点で非推奨となり、このリリースではサポートされなくなりました。

NGINX Plus R26にアップグレードする前に、NGINX設定ファイルのjs_includejs_importに置き換え、さらにNGINX設定内で参照される関数のJavaScriptファイルにexport文を追加してください。以下の手順に従ってください。

  1. NGINXの設定ファイルを変更します。

    • js_includejs_import に置き換え、暗黙に指定しているモジュール名 (拡張子 .js を除いたディレクティブの JavaScript ファイル名) を記録しておいてください。

    • JavaScript の関数を参照する各ディレクティブで、関数名の前に module_name を付けます。関数名は以下のディレクティブの最初のパラメータとなります。

      js_set[HTTP][Stream]ディレクティブでは第2パラメータとなります。

    例を示します。

    js_set $foo myFunction;

    js_set $foo module_name.myFunction;

    へ変更してください。

  2. NGINXの設定ファイルから参照する関数を定義したJavaScriptファイル(module_name.js)を編集してください。各ファイルに以下のような export 文を追加し、参照する関数の名前を付けます。

    export default { myFunction, otherFunction }

    export文は.jsファイルのどこに書いてもかまいませんが、慣例として関数の直上かファイルの末尾に置かれます。

Cookie-Flagモジュールの廃止

サードパーティ製のCookie-FlagモジュールはNGINX Plus R23で非推奨となり、その際に発表されたように、本リリース時点でNGINXモジュールリポジトリから入手できなくなりました。

NGINX Plus R26 にアップグレードする前に、NGINX の設定を編集して set_cookie_flag ディレクティブ(非推奨モジュールで定義)で記述した箇所をNGINX Plusが提供するproxy_cookie_flags ディレクティブに置き換えてください。

TLSネゴシエーションの NPNプロトコルのサポート終了

NGINXがTLSおよびHTTP/2接続を確立する方法が更新されました。NGINXとクライアント(通常はブラウザ)間のTLSハンドシェイクの一部として、ハンドシェイクによって確立されたセッションでどの通信プロトコルを使用するかを交渉します(ほとんどの場合、交渉によってセッションがHTTP 1.xからHTTP/2にアップグレードされます)。TLS の Next Protocol Negotiation (NPN) 拡張がこの目的のために最初に使用された方法でしたが、NPN は現在では古い指定方法となり、RFC 7301 として公開された Application-Layer Protocol Negotiation (ALPN) 拡張に取って代わられています。

NGINX Plus R26はNPNをサポートしなくなったため、クライアントはALPNを使用する必要があります。

さらに、ALPNの実装は拡張され、強化されています(強化されたTLSハンドシェイクを参照)。

以前のNGINX Plusソフトウェアリポジトリの更新終了

NGINX Plus R24のリリース時に、すべてのNGINXソフトウェアのパッケージリポジトリが再編成され、その結果、NGINX Plusのインストール手順が変更されました。

NGINX Plus をインストールまたはアップグレードすると、オペレーティングシステムのパッケージマネージャ(aptyum、または同等のもの)が NGINX Plus 用のソフトウェアリポジトリで構成されます。

古い plus-pkgs.nginx.com レポジトリを使用するように構成された既存のシステム(NGINX Plus R23以前を実行しているもの)でNGINX Plus R26にアップグレードする場合、新しい pkgs.nginx.com/plus レポジトリを参照するようにパッケージマネージャをアップデートする必要があります。F5 Knowledge Baseに記載されている手順を参照してください。

NGINX Plus R26の初期インストールを行う場合は、『NGINX Plus Admin Guide』の「NGINX Plusのインストール」を参照してください。

NGINX Plus R26は、今後アップデートを行わない旧リポジトリでは利用できません。

NGINX Plus API の OpenAPI 仕様へのアクセス方法の変更

NGINX Plus ソフトウェアパッケージには、NGINX Plus API の YAML 形式の OpenAPI 仕様Swagger UI が含まれなくなりました。詳細については、NGINX Plus Admin Guide の内容を確認してください。

対応プラットフォームの変更

新たに以下のプラットフォームがサポートされます。

  • Alpine Linux 3.15 (x86_64, arm64)
  • The IBM Z Platform (s390x) with CentOS 8.1+, RHEL 8.1+, and Ubuntu 20.04 (詳細は Support for IBM Z s390x Architecture を確認ください。)

以下プラットフォームはサポート対象外となります。

  • Alpine Linux 3.11 (最も古いサポートバージョンは 3.12 です。)

以下プラットフォームはNGINX Plus R27でサポート対象外となる予定です。

  • Power8 architecture (ppc64le)
  • CentOS 8.1+
  • Alpine Linux 3.12

新機能の詳細

JSON KeyキャッシングによるJWT検証の高速化

JSON Web Tokenを検証する際、NGINXはJSON Web Key Sets(JWKS)を使用してトークンの署名を検証したり、トークンを復号化したりします。JWKSは設定ファイルに保存するか、HTTPリクエストによって外部サービスから取得することができます。さらに、JWKSをメモリにキャッシュすることで、いくつかの利点があります。

  • CPU使用率の大幅な削減
  • リクエストレイテンシーの短縮
  • キャッシュ処理の一環として、JWKSキーがJSONから暗号処理に最適なバイナリ形式に変換されるため、JWT検証を効率化できる。

JWKSをメモリ上にキャッシュするには、新しいauth_jwt_key_cacheディレクティブを含め、各キーセットの有効期限を指定します(以下の例では3時間と指定しています)。


JWKが外部サーバーから取得される場合、標準的なコンテンツキャッシングを構成し、proxy_cache_use_staleディレクティブを含めることも推奨します。これは、NGINX Plusに、バックグラウンドでリフレッシュされている間、期限切れのJWKSの提供を継続するよう指示します。


JWKSキャッシュに加え、コンテンツキャッシュを行うメリットは2つあります。

  • レジリエンス(復元力) – JWKSは、有効期限が切れてもキャッシュから取得することができます。これは、JWKSプロバイダが一時的に利用できない場合の復元力を高めるが、セキュリティリスクの増加というトレードオフがあります。

  • 認証サーバーへの影響 – キャッシュされたJWKSの期限切れは、JWKSキャッシュが単独で使用されている場合、コンテンツキャッシュと併用されている場合のそれぞれで、認証サーバーに異なる影響を与えます。

    • JWKSのキャッシュを単独で利用する場合、キャッシュに期限切れのJWKSの新しいバージョンが再投入されるまで、受信するすべての認証リクエストは認証サーバーに転送されます。認証サーバーの応答が遅い場合、JWKSに対するHTTPリクエストの繰り返しが急激に増加する可能性があります。この余分な負荷は、認証サービスを圧迫し、問題を悪化させるかもしれません。

    • コンテンツキャッシュにより期限の切れたJWKSの提供が有効になっている場合、JWKSに対する1つのリクエストのみが認証サーバーに転送され、それ以降のリクエストはNGINXがコンテンツキャッシュを完了した後、適切に応答するようキューに入れられます。この結果、認証サービスに対する要求が少なくなります(したがって、リソースの消費量も少なくなります)。

TLSハンドシェイクの強化

ALPACAなど、TLSに対する攻撃が増加しています。エクスプロイトに対する積極的な防御の一環として、NGINXのTLS接続の取り扱いを強化しました。

Application-Layer Protocol Negotiation (ALPN) は TLS ハンドシェイクのオプション拡張で、TLS ハンドシェイク中にクライアントとサーバーが、ハンドシェイクによって確立された暗号化セッションで使用するレイヤー 7 プロトコルを選択するために使用されます。ALPN の最も一般的な使用例は、ブラウザと Web またはアプリサーバー間のセッションで HTTP/1.x から HTTP/2 へのアップグレードをネゴシエートすることです。

NGINX Plus は、確立されたセッションが NGINX 設定のコンテキストと一致しないプロトコルをクライアントが ALPN 経由で提案した場合、TLS ハンドシェイクを拒否するようになりました。たとえば、http{} コンテキストで定義された仮想サーバーは HTTP の ALPN プロトコル ID を必要とし、mail{} コンテキストの仮想サーバーは SMTP, POP, または IMAP のプロトコル ID を必要とします。

NGINX Plus R26では、ネゴシエートされたプロトコルを捕捉するために$ssl_alpn_protocol[HTTP][Stream]変数を導入しています。(NGINX Plus R15stream{} コンテキストに導入された $ssl_preread_alpn_protocols 変数は、ハンドシェイク中にクライアントによってアドバタイズされたすべてのプロトコルのリストを取得します。)

以下の設定例では、アクセスログのエントリの alpn= フィールドにプロトコルを含めるために $ssl_alpn_protocol を使用し、 alpn という名称のログ形式を定義しています。


stream{}コンテキスト内の新しいssl_alpnディレクティブは、NGINX Plusがどのプロトコルを受け入れるかを定義します。ディレクティブを省略すると、NGINX Plus がクライアントから提示されたすべてのプロトコルを考慮するようになります。


NGINX JavaScriptモジュールの機能強化

NGINX Plus R26は、NGINX JavaScriptモジュール(njs)のバージョン 0.7.2を搭載し、2つの機能強化を行いました。

注意:このセクションは、非同期および暗号化操作のためのJavaScriptコンストラクトを理解していることを前提としています。コードスニペットの完全な解析は、このブログでは取り扱いません。

[編集部 – このセクションで説明するユースケースは、NGINX JavaScriptモジュールの数あるユースケースのうちの一部にすぎません。完全なリストについては、NGINX JavaScriptモジュールの使用例を参照してください。]

非同期関数のサポート強化

PHPのような多くの一般的なスクリプト言語では、コマンドと関数は同期的に実行されます。つまり、スクリプトが関数を呼び出した後、関数が結果を返すまで実行が一時停止されます。

JavaScriptは非同期処理も可能です。非同期で関数を呼び出すと、その関数から返ってくる結果を待たずにスクリプトの実行が継続されます。

このスクリプトの例を見てみましょう。


njsランタイムは定義されたタイムアウトの経過を待たないので、空のレスポンスを返します(もし待っていたら、出力はb,aになります)。

$ curl http://127.0.0.1/
$ 

非同期処理を正しく処理することは、意図した結果を得るために重要なことは明らかです。JavaScriptはこれを行うための多くの方法を提供しますが、一般的なNGINXのユースケースでは、単に実行フローを同期にする方法で非同期関数をラップすることが望ましいことがよくあります。そこで、Promiseオブジェクトとasyncawaitというキーワードが登場します。

ECMAScript 6(JavasScriptの言語仕様ECMA-262の第6版)では、非同期関数の戻り値型としてPromiseオブジェクトを定義しています。これは、以下3つの状態のうちの1つとなっています。

  • fulfilled – 操作が正常に完了した。
  • rejected – 操作に失敗した。
  • pending – 初期状態(fulfilledでもrejectedでもない)。

JavaScriptの関数にasyncキーワードを定義すると、関数の戻り値の型がPromiseに設定されます。asyncawaitは、Promiseオブジェクトを扱うnjs関数を書くときに重要です。

この例を見てみましょう。


fs.readFile関数(12行目)は、Promiseを返します。これは、ファイルが user.text という名前の場合にのみ fs.readFile() が呼び出されるように、カスタムの非同期関数でラップされています。awaitがあるため、ラッピング関数はその後Promiseを待ってデータを返します。

fs.readFile()を別の関数でラップすると、エラーをキャッチしやすくなります。非同期関数で例外が発生すると、Promiseの状態がrejectedに設定されるからです。また、9行目をrejectedPromiseを返すステートメントに置き換える方法もあります。


また、Promiseオブジェクトを直接操作することも可能です。次の例では、Promise.resolve()関数がp1p2のそれぞれについてPromiseを返しています。Promise.all関数は,p1p2の両方のプロミスが解決されるのを待ってから,結果を返します。


これで、curlコマンドの出力は私たちが望むものになりました(タイムアウト値が短いため、bが最初にリターンされることに注意してください)。

$ curl http://127.0.0.1/
b,a
$ 

WebCrypto APIによる新しい暗号化機能

NGINX JavaScriptは、WebCrypto APIを通じて強化された暗号化機能を利用できるようになりました。一般的なnjsの暗号のユースケースは以下の通りです。

  • セッションID用の安全な乱数の生成
  • メッセージ、データ、Cookieの暗号化・復号化
  • 対称型および非対称型暗号アルゴリズムを使用したデジタル署名の作成と検証

以下のnjsのコードは、乱数を生成します。


そして、以下のNGINX Plusの設定は、njsのコードを呼び出します。


この関数の出力は、次のような乱数となります。

$ curl 127.0.0.1
23225320050,3668407277,1101267190,2061939102,2687933029,2361833213,32543985,4162087386

WebCryptoのgetRandomValues 関数は、安全な乱数とWebCrypto全般を使い始めるための素晴らしいエントリーポイントです。その実装は非常にシンプルで、この関数は Promise を返すのではなく、直接結果を返します。

しかし、他のより強力な WebCrypto 暗号関数の中には、非同期で動作するものがあります。例えば、сrypto.subtle.digest()のドキュメントには、次のように記載されています。

与えられたデータのダイジェストを生成する。引数として、使用するダイジェストアルゴリズムとダイジェストの対象となるデータを渡します。その結果、ダイジェストと共にPromiseを返します。

したがって、сrypto.subtle.digest()を直接呼び出すと、非同期関数でラップされていない限り、その結果が次のステップで利用可能になることは保証されません。そこで、ここでは asyncawait キーワードを使用して関数でラップし、関数が戻る前にハッシュ変数に結果が入力されるようにします。


以下の NGINX Plusの設定内の js_set ディレクティブは、変数 $hosthashsetReturnValue 関数が返す値 (host_hash 関数でラップされたもの) を代入します。


以下は、ホスト名example.comをハッシュ化する例です。

$ curl -H "Host: example.com" 127.1
#
e8e624a82179b53b78364ae14d14d63dfeccd843b026bc8d959ffe0c39fc4ded1f4dcf4c8ebe871e657a12db6f11c3af87c9a1d4f2b096ba3deb56596f06b6f4

NGINX Plus R26のその他の強化点

IBM Z (s390x) アーキテクチャのサポート

モダンなアプリケーションの実装は、利用可能なあらゆるデジタルな実行環境を変化させているため、NGINXのように、必須で長期に渡って利用されるコンポーネントもその変化に追従することが重要です。そこで、IBM Z(s390x)アーキテクチャ上のNGINX PlusをCentOS 8.1+, RHEL 8.1+ およびUbuntu 20.04 でサポートできるようになりました。既存のメインフレーム資産で最新のアプリケーションをホストしようとしている組織は、NGINXとNGINX PlusをソフトウェアベースのWebサーバー、ロードバランサー、リバースプロキシ、コンテンツキャッシュ、APIゲートウェイとして導入することができるようになりました。

StreamモジュールにおけるTCPハーフクローズ対応

新しい proxy_half_close ディレクティブは、stream{} コンテキストでの効率性を高めるために、TCP 接続の各ディレクションの独立した操作を可能にします。

PCRE2ライブラリのサポート

NGINX Plusの以前のバージョンでは、NGINXの設定で使用される正規表現を評価するためにPerl Compatible Regular Expression (PCRE)ライブラリ(バージョン1)を使用していました。この重要なオープンソースプロジェクトは、最近終了し、PCRE2に取って代わられました。NGINX Plusは、PCREとPCRE2の両方をサポートし、基盤となるオペレーティングシステムで利用可能なバージョンを自動的に使用するようになりました。設定の変更は必要ありません。

NGINX Plusのアップグレードまたは試用

NGINX Plusを実行している場合、できるだけ早くNGINX Plus R26にアップグレードすることを強くお勧めします。また、いくつかの追加修正と改善点をピックアップしておくと、サポートチケットを発行する必要があるときにNGINXにとって役立ちます。

NGINX Plusをまだお試しでない方は、セキュリティ、ロードバランシング、APIゲートウェイとして、あるいは強化された監視・管理APIを備えたフルサポートのWebサーバーとして、ぜひお試しください。30日間の無料トライアルで、今すぐ始めることができます。

Hero image
NGINXクックブック 設定レシピ集(日本語版)

待望の【O'Reilly】NGINX Cookbook日本語版がついに完成!NGINXクックブックは、NGINXを最大限に活用する方法を解説しています。



著者について

Robert Haynes

Technical Marketing Manager

About F5 NGINX

F5 NGINXについて
F5, Inc.は、人気のオープンソースプロジェクト「NGINX」を支援しています。NGINXはモダンアプリケーションを開発・構築するためのテクノロジースイートを提供しています。NGINXとF5製品との併用で、コードからユーザーまでの広範なアプリケーション領域をサポートし、マルチクラウドアプリケーションサービスとしてNetOpsとDevOps間の課題を解決します。

詳しくはnginx.co.jpをご覧ください。Twitterで@nginxをフォローして会話に参加することもできます。