これは、NGINX Open Source と NGINX Plus を API ゲートウェイとして導入するシリーズの最初のブログ投稿です。
位置
書き換えルールの代わりに、ブロックを使用してリクエストをルーティングします。注記: 特に記載がない限り、この記事のすべての情報は、NGINX Open Source と NGINX Plus の両方に適用されます。 読みやすくするために、このブログの残りの部分では単に「NGINX」と呼びます。
現代のアプリケーション アーキテクチャの中心となるのは HTTP API です。HTTP を使用すると、アプリケーションを迅速に構築し、簡単に保守できるようになります。 HTTP API は、単一目的のマイクロサービスから包括的なモノリスまで、アプリケーションの規模に関係なく、共通のインターフェースを提供します。 HTTP を使用することで、ハイパースケールのインターネット プロパティをサポートする Web アプリケーション配信の進歩を利用して、信頼性が高くパフォーマンスの高い API 配信を提供することもできます。
マイクロサービス アプリケーションにおける API ゲートウェイの重要性に関する優れた入門書については、 「マイクロサービスの構築」を参照してください。 APIゲートウェイの使用 私たちのブログで。
最先端の高性能軽量リバース プロキシおよびロード バランサーである NGINX は、API トラフィックの処理に必要な高度な HTTP 処理機能を備えています。 これにより、NGINX は API ゲートウェイを構築するための理想的なプラットフォームになります。 このブログ記事では、いくつかの一般的な API ゲートウェイの使用例について説明し、効率的でスケーラブルかつ保守しやすい方法でそれらを処理するように NGINX を構成する方法を示します。 本番環境の展開の基礎となる完全な構成について説明します。
API ゲートウェイの主な機能は、バックエンドで API がどのように実装または展開されているかに関係なく、複数の API に対して単一の一貫したエントリ ポイントを提供することです。 すべての API がマイクロサービス アプリケーションであるわけではありません。 当社の API ゲートウェイでは、マイクロサービスへの部分的な移行が行われている既存の API、モノリス、アプリケーションを管理する必要があります。
このブログ投稿では、在庫管理用の仮想 API「Warehouse API」について説明します。 さまざまなユースケースを説明するために、サンプル構成コードを使用します。 Warehouse API は、JSON リクエストを消費し、JSON 応答を生成する RESTful API です。 ただし、API ゲートウェイとして展開する場合、JSON の使用は NGINX の制限や要件ではありません。NGINX は、API 自体で使用されるアーキテクチャ スタイルやデータ形式に依存しません。
Warehouse API は、個別のマイクロサービスのコレクションとして実装され、単一の API として公開されます。在庫と価格設定のリソースは個別のサービスとして実装され、異なるバックエンドにデプロイされます。 したがって、API のパス構造は次のようになります。
API
└── 倉庫
├── 在庫
└── 価格設定
たとえば、現在の倉庫の在庫を照会するには、クライアント アプリケーションが/api/warehouse/inventoryに HTTP GET
リクエストを送信します。
NGINX を API ゲートウェイとして使用する利点の 1 つは、既存の HTTP トラフィックに対してリバース プロキシ、ロード バランサ、Web サーバーとして同時に機能しながら、その役割を実行できることです。 NGINX がすでにアプリケーション配信スタックの一部になっている場合は、通常、別の API ゲートウェイをデプロイする必要はありません。 ただし、API ゲートウェイに期待されるデフォルトの動作の一部は、ブラウザベースのトラフィックに期待される動作とは異なります。 そのため、API ゲートウェイ構成を、ブラウザベースのトラフィックの既存 (または将来の) 構成から分離します。
この分離を実現するために、多目的 NGINX インスタンスをサポートし、CI/CD パイプラインを通じて構成の展開を自動化するための便利な構造を提供する構成レイアウトを作成します。 結果として、 /etc/nginxの下のディレクトリ構造は次のようになります。
etc/
└── nginx/
├── api_conf.d/ ………………………………… API ごとの設定のサブディレクトリ
│ └── warehouse_api.conf …… Warehouse API の定義とポリシー
├── api_backends.conf ………………… バックエンド サービス (アップストリーム)
├── api_gateway.conf …………………… API ゲートウェイ サーバーの最上位設定
├── api_json_errors.conf ………… JSON 形式の HTTP エラー応答
├── conf.d/
│ ├── ...
│ └── existing_apps.conf
└── nginx.conf
すべての API ゲートウェイ構成のディレクトリとファイル名には、 api_というプレフィックスが付きます。 これらの各ファイルとディレクトリは、以下で詳しく説明するように、API ゲートウェイのさまざまな機能を有効にします。 warehouse_api.confファイルは、以下で説明する、さまざまな方法で Warehouse API を定義する構成ファイルの汎用的な代替ファイルです。
すべての NGINX 構成は、メイン構成ファイルnginx.confから始まります。 API ゲートウェイ構成を読み込むには、ゲートウェイ構成を含むファイルapi_gateway.conf (以下の 28 行目) を参照するinclude
ディレクティブをnginx.confのhttp
ブロックに追加します。 デフォルトのnginx.confファイルでは、 include
ディレクティブを使用して、 conf.dサブディレクトリからブラウザベースの HTTP 構成を取得することに注意してください (行 29)。 このブログ投稿では、読みやすさを向上させ、構成の一部を自動化できるようにするために、 include
ディレクティブを多用しています。
api_gateway.confファイルは、NGINX を API ゲートウェイとしてクライアントに公開する仮想サーバーを定義します。 この構成では、API ゲートウェイによって公開されたすべての API が、単一のエントリ ポイントhttps://api.example.com/ (行 9) で公開され、行 12 から 17 で構成されている TLS によって保護されます。 この構成は純粋に HTTPS であり、プレーンテキストの HTTP リスナーは存在しないことに注意してください。 API クライアントは正しいエントリ ポイントを認識し、デフォルトで HTTPS 接続を行うことを期待します。
この構成は静的であることが意図されています。個々の API とそのバックエンド サービスの詳細は、20 行目のinclude
ディレクティブによって参照されるファイルで指定されます。 23 行目から 26 行目はエラー処理に関するもので、以下の「エラーへの対応」で説明します。
一部の API は単一のバックエンドで実装される場合もありますが、通常は、回復力や負荷分散の理由から、複数のバックエンドが存在することが想定されます。 マイクロサービス API では、各サービスに個別のバックエンドを定義し、それらが一緒になって完全な API として機能します。ここでは、Warehouse API は、それぞれ複数のバックエンドを持つ 2 つの個別のサービスとしてデプロイされています。
API ゲートウェイによって公開されるすべての API のすべてのバックエンド API サービスは、 api_backends.confで定義されます。 ここでは、各アップストリーム
ブロックで複数の IP アドレスとポートのペアを使用して、API コードがデプロイされている場所を示しますが、ホスト名も使用できます。 NGINX Plus サブスクライバーは、ダイナミックDNS ロード バランシングを利用して、新しいバックエンドをランタイム構成に自動的に追加することもできます。
Warehouse API は、次の例に示すように、ネストされた構成内の複数のロケーション
ブロックによって定義されます。 外側のロケーション
ブロック ( /api/warehouse ) は基本パスを識別し、その下にネストされたロケーションがバックエンド API サービスにルーティングされる有効な URI を指定します。 外側のブロックを使用すると、API 全体に適用される共通ポリシーを定義できます (この例では、6 行目のログ記録構成)。
NGINX には、リクエスト URI を構成のセクションに一致させるための非常に効率的で柔軟なシステムがあります。 場所
ディレクティブの順序は重要ではありません。最も具体的な一致が選択されます。 ここで、10 行目と 14 行目のネストされた場所は、外側の場所
ブロックよりも具体的な 2 つの URI を定義します。各ネストされたブロック内のproxy_pass
ディレクティブは、リクエストを適切なアップストリーム グループにルーティングします。 特定の URI に対してより具体的なポリシーを提供する必要がない限り、ポリシー構成は外部の場所から継承されます。
ネストされた場所のいずれにも一致しないURIは、レスポンスを返すキャッチオールディレクティブ(行18)を含む外側の場所によって処理されます。 404
(ない
見つかった)
すべての無効な URI に対して。
API 定義には、広範と厳密の 2 つのアプローチがあります。 各 API に最も適したアプローチは、API のセキュリティ要件と、バックエンド サービスが無効な URI を処理することが望ましいかどうかによって異なります。
上記のwarehouse_api_simple.confでは、Warehouse API に対して幅広いアプローチを使用して、10 行目と 14 行目に URI プレフィックスを定義し、プレフィックスの 1 つで始まる URI が適切なバックエンド サービスにプロキシされるようにしています。 この広範なプレフィックスベースの場所の一致により、次の URI への API リクエストはすべて有効になります。
/api/倉庫/在庫
/api/倉庫/在庫/
/api/倉庫/在庫/foo
/api/倉庫/在庫foo
/api/warehouse/inventoryfoo/bar/
各リクエストを適切なバックエンド サービスにプロキシすることだけを考慮する場合、広範なアプローチにより、最も高速な処理と最もコンパクトな構成が実現します。 一方、より正確なアプローチでは、利用可能な各 API リソースの URI パスを明示的に定義することで、API ゲートウェイが API の完全な URI 空間を理解できるようになります。 正確なアプローチを採用して、Warehouse API の URI ルーティングの次の構成では、完全一致 ( =
) と正規表現 ( ~
) の組み合わせを使用して、すべての有効な URI を定義します。
この構成はより詳細ですが、バックエンド サービスによって実装されるリソースをより正確に説明します。 これには、正規表現のマッチングに若干の追加オーバーヘッドが発生しますが、不正なクライアント要求からバックエンド サービスを保護できるという利点があります。 この設定を行うと、NGINX は一部の URI を受け入れ、その他を無効として拒否します。
有効なURI | 無効なURI | |
---|---|---|
/api/倉庫/在庫 | /api/倉庫/在庫/ | |
/api/倉庫/在庫/棚/foo | /api/倉庫/在庫foo | |
/api/倉庫/在庫/棚/foo/ボックス/バー | /api/倉庫/在庫/棚 | |
/api/倉庫/在庫/棚/-/ボックス/- | /api/倉庫/在庫/棚/foo/bar | |
/api/ウェアハウス/価格設定/baz | /api/ウェアハウス/価格設定 | |
/api/warehouse/価格設定/baz/pub |
正確な API 定義を使用すると、既存の API ドキュメント形式を使用して API ゲートウェイの構成を制御できるようになります。 OpenAPI 仕様(旧称 Swagger) から NGINX API 定義を自動化することが可能です。 この目的のためのサンプル スクリプトは、このブログ投稿の Gist の中に提供されています。
API が進化するにつれて、厳密な下位互換性が失われ、クライアントの更新が必要になるような変更が必要になる場合があります。 そのような例の 1 つは、API リソースの名前が変更されたり、移動されたりする場合です。 ウェブブラウザとは異なり、APIゲートウェイはクライアントにリダイレクト(コード301
(
永久に移動)
)新しい場所に名前を付けます。 幸いなことに、API クライアントを変更するのが現実的でない場合は、クライアント要求をその場で書き換えることができます。
次の例では、上記のwarehouse_api_simple.confと同じ広範なアプローチを使用していますが、この場合の構成は、価格設定サービスが在庫サービスの一部として実装されていた Warehouse API の以前のバージョンを置き換えています。 3 行目の書き換え
ディレクティブは、古い価格設定リソースへのリクエストを新しい価格設定サービスへのリクエストに変換します。
HTTP API とブラウザベースのトラフィックの主な違いの 1 つは、エラーがクライアントに伝達される方法です。 NGINX を API ゲートウェイとしてデプロイする場合、API クライアントに最適な方法でエラーを返すように構成します。
最上位レベルの API ゲートウェイ構成には、エラー応答の処理方法を定義するセクションが含まれています。
の エラーページ
23行目のディレクティブは、リクエストがどのAPI定義にも一致しない場合にNGINXが返すことを指定します。 400
(悪い
リクエスト
) デフォルトではなくエラー 404
(ない
見つかった
) エラー。 この (オプションの) 動作では、API クライアントが API ドキュメントに含まれる有効な URI に対してのみリクエストを行う必要があり、権限のないクライアントが API ゲートウェイを通じて公開された API の URI 構造を発見することを防ぎます。
24 行目は、バックエンド サービス自体によって生成されたエラーを示します。 処理されない例外には、クライアントに送信したくないスタック トレースやその他の機密データが含まれている場合があります。 この構成では、標準化されたエラー応答をクライアントに送信することで、さらに高いレベルの保護が追加されます。
標準化されたエラー応答の完全なリストは、25 行目のinclude
ディレクティブによって参照される別の構成ファイルで定義されており、その最初の数行を以下に示します。 JSON 以外のエラー形式が望ましい場合は、 api_gateway.confの 26 行目のdefault_type
値を一致するように変更して、このファイルを変更できます。 また、各 API のポリシー セクションに個別のinclude
ディレクティブを配置して、グローバル応答をオーバーライドするエラー応答の別のファイルを参照することもできます。
この構成では、無効な URI に対するクライアント要求に対して次の応答が返されます。[terminal]$ curl -i https://api.example.com/foo HTTP/1.1 400 Bad Request Server: nginx/1.19.5 Content-Type: application/json Content-Length: 39 接続: キープアライブ {"status":400,"message":"不正な要求"}[/terminal]
何らかの認証によって保護せずに API を公開することは珍しいことです。 NGINX は、API を保護し、API クライアントを認証するためのいくつかのアプローチを提供します。 通常の HTTP 要求にも適用されるアプローチについては、 IP アドレスベースのアクセス制御リスト(ACL)、デジタル証明書認証、およびHTTP 基本認証のドキュメントを参照してください。 ここでは、API 固有の認証方法に焦点を当てます。
API キーは、クライアントと API ゲートウェイが知っている共有秘密です。 API キーは、本質的には、長期認証情報として API クライアントに発行される長くて複雑なパスワードです。 API キーの作成は簡単です。この例のようにランダムな数字をエンコードするだけです。
$ openssl rand -base64 18 7B5zIqmRGXmrJTFmKa99vcit
最上位の API ゲートウェイ構成ファイルapi_gateway.confの 2 行目に、 api_keys.confというファイルを含めます。このファイルには、クライアントの名前またはその他の説明で識別される各 API クライアントの API キーが含まれています。 そのファイルの内容は次のとおりです。
API キーはマップ
ブロック内で定義されます。 map
ディレクティブは 2 つのパラメータを取ります。 最初は、API キーが見つかる場所を定義します。この場合は、 $http_apikey
変数でキャプチャされたクライアント要求のapikey
HTTP ヘッダー内です。 2 番目のパラメーターは新しい変数 ( $api_client_name
) を作成し、最初のパラメーターがキーと一致する行の 2 番目のパラメーターの値に設定します。
たとえば、クライアントが API キー7B5zIqmRGXmrJTFmKa99vcit
を提示すると、 $api_client_name
変数はclient_one
に設定されます。 この変数は、認証されたクライアントを確認するために使用でき、より詳細な監査のためにログ エントリに含めることができます。 マップ
ブロックの形式はシンプルで、既存の資格情報ストアからapi_keys.confファイルを生成する自動化ワークフローに簡単に統合できます。
ここでは、「広範な」構成 ( warehouse_api_simple.conf ) を修正して、認証の決定を指定された場所に委任するauth_request
ディレクティブをポリシー セクションに含めることで、API キー認証を有効にします。
auth_request
ディレクティブ (7 行目) を使用すると、たとえば、 OAuth 2.0 トークン イントロスペクションなどの外部認証サーバーによって認証を処理できます。 この例では、代わりに、API キーを検証するためのロジックを、 /_validate_apikeyという次のロケーション
ブロックの形式で、最上位の API ゲートウェイ構成ファイルに追加します。
30 行目の内部
ディレクティブは、この場所に外部クライアントが直接アクセスできないことを意味します ( auth_request
によってのみアクセス可能)。 クライアントは、 apikey
HTTP ヘッダーに API キーを提示する必要があります。 このヘッダーが欠落しているか空の場合(32行目)、401
認証が必要であることをクライアントに通知する(無許可の)
応答。 35行目は、APIキーがマップ
ブロックのどのキーとも一致しない場合の処理です。この場合、 api_keys.confの2行目のデフォルト
パラメータは$api_client_nameを
空の文字列に設定し、403
認証が失敗したことをクライアントに通知する(禁止)
応答。 どちらの条件も一致しない場合は、APIキーは有効であり、ロケーションは204
(
コンテンツなし)
応答。
この構成により、Warehouse API は API キー認証を実装するようになりました。
$ curl https://api.example.com/api/warehouse/pricing/item001 {"status":401,"message":"Unauthorized"} $ curl -H "apikey: thisIsInvalid" https://api.example.com/api/warehouse/pricing/item001 {"status":403,"message":"Forbidden"} $ curl -H "apikey: 7B5zIqmRGXmrJTFmKa99vcit" https://api.example.com/api/warehouse/pricing/item001 {"sku":"item001","price":179.99}
JSON Web Token (JWT) は、API 認証にますます使用されるようになっています。 ネイティブ JWT サポートは NGINX Plus 専用であり、ブログの「JWT と NGINX Plus を使用した API クライアントの認証」で説明されているように、JWT の検証が可能になります。 サンプル実装については、パート 2 の「特定のメソッドへのアクセスの制御」を参照してください。
このシリーズの最初のブログでは、NGINX Open Source と NGINX Plus を API ゲートウェイとして導入するための完全なソリューションについて詳しく説明します。 このブログで説明したファイルの完全なセットは、GitHub Gist リポジトリから確認およびダウンロードできます。
このシリーズの他の投稿もご覧ください:
NGINX Plus をお試しいただくには、今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、使用事例についてご相談ください。
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"