ブログ | NGINX

JWT と NGINX Plus を使用した API クライアントの認証

NGINX-F5 水平黒タイプ RGB の一部
リアム・クリリー サムネイル
リアム・クリリー
2021年12月2日公開

JSON Web Token (JWT、「ジョット」と発音) は、ID 情報を交換するためのコンパクトで移植性が高い手段です。 JWT 仕様はOpenID Connectの重要な基盤であり、OAuth 2.0 エコシステムにシングル サインオン トークンを提供します。 JWT は、それ自体が認証資格情報としても使用でき、従来の API キーよりも Web ベースの API へのアクセスを制御するのに適した方法です。

NGINX Plus R10 以降では、JWT を直接検証できます。 このブログ記事では、NGINX Plus を API ゲートウェイとして使用し、API エンドポイントへのフロントエンドを提供し、JWT を使用してクライアント アプリケーションを認証する方法について説明します。

ネイティブ JWT サポートは NGINX Plus でのみ利用可能であり、NGINX Open Source では利用できません。

エディタ – このブログ投稿は 更新されました 2021年12月に 認証_jwt_require 指令は NGINX プラス R25。 ディレクティブの詳細については、 NGINX Plus R25 を発表したブログの「カスタム JWT 検証ルール」を参照してください。

NGINX Plus R15以降では、OpenID Connect 1.0 の「認証コードフロー」も制御できるため、ほとんどの主要な ID プロバイダーとの統合が可能になります。 詳細については、 「NGINX Plus R15 の発表」<.htmlspan>を参照してください。

JWT の構造

JWT には、ヘッダー、ペイロード、署名の 3 つの部分があります。 送信時には次のようになります。 読みやすくするために改行を追加し(実際の JWT は単一の文字列です)、3 つの部分を区別するために色分けしました。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0= . VGYHWPterIaLjRi0LywgN3jnDUQbSsFptUw99g2slfc

示されているように、ピリオド ( . ) はヘッダー、ペイロード、および署名を区切ります。 ヘッダーとペイロードはBase64 でエンコードされたJSON オブジェクトです。 署名はalgヘッダーで指定されたアルゴリズムを使用して暗号化されます。これはサンプル JWT をデコードすると確認できます。

  エンコード 解読
ヘッダ eyJhbGciOiJIUzI1NiIsInR5cCI6Ik
pXVCJ9
{
「代替」: 「HS256」、
「タイプ」: 「JWT」
}
ペイロード ewogICAgInN1YiI6ICJsYzEiLAogICAgImVtYWlsIjogImxpYW0uY3JpbGx5QG5naW54LmNvbSIsCn0= {
"サブ": "lc1",
「メール」: 「liam.crilly@nginx.com」、
}

JWT 標準では、いくつかの署名アルゴリズムが定義されています。 この例のHS256 という値は HMAC SHA-256 を指し、このブログ投稿のすべてのサンプル JWT にこれを使用しています。 NGINX Plus は、標準で定義されているHS xxxRS xxx 、およびES xxx署名アルゴリズムをサポートしています。 JWT に暗号署名できるため、認証資格情報として使用するのに最適です。

API キーとしての JWT

API クライアント (API リソースを要求するリモート ソフトウェア クライアント) を認証する一般的な方法は、一般にAPI キーと呼ばれる共有シークレットを使用することです。 従来の API キーは、本質的には、クライアントがリクエストごとに追加の HTTP ヘッダーとして送信する長くて複雑なパスワードです。 提供された API キーが有効なキーのリストに含まれている場合、API エンドポイントは要求されたリソースへのアクセスを許可します。 通常、API エンドポイントは API キー自体を検証しません。代わりに、API ゲートウェイが認証プロセスを処理し、各リクエストを適切なエンドポイントにルーティングします。 これにより、計算のオフロードに加えて、高可用性や多数の API エンドポイントへの負荷分散など、リバース プロキシに伴う利点も得られます。

従来の API キーを使用した API クライアントと JWT 認証
APIゲートウェイは、リクエストを渡す前にキーレジストリを参照してAPIキーを検証します。
APIエンドポイントへ

異なる API クライアントに異なるアクセス制御とポリシーを適用するのは一般的です。 従来の API キーでは、API キーを属性セットと一致させるための検索が必要です。 すべてのリクエストに対してこの検索を実行すると、システム全体のレイテンシに当然の影響が及びます。 JWT では、これらの属性が埋め込まれているため、個別の検索が不要になります。

JWT を API キーとして使用すると、ベスト プラクティスの認証テクノロジと ID 属性を交換するための標準ベースのスキーマを組み合わせた、従来の API キーに代わる高性能な手段が提供されます。

JWT と NGINX Plus を使用した API クライアントと JWT 認証
NGINX Plusは、リクエストをAPIエンドポイントに渡す前にJWTを検証します

NGINX Plus を認証 API ゲートウェイとして構成する

JWT を検証するための NGINX Plus の設定は非常にシンプルです。

アップストリーム api_server {
server 10.0.0.1;
server 10.0.0.2;
}

server {
listen 80;

location /products/ {
auth_jwt "製品 API";
auth_jwt_key_file conf/api_secret.jwk;
proxy_pass http://api_server;
}
}

最初に行うことは、API エンドポイントをホストするサーバーのアドレスをアップストリームブロックに指定することです。 ロケーションブロックは、 /products/で始まる URL へのすべてのリクエストを認証する必要があることを指定します。 auth_jwtディレクティブは、返される認証レルムを定義します(401認証が失敗した場合はステータス コードを返します。

auth_jwt_key_fileディレクティブは、NGINX Plus に JWT の署名要素を検証する方法を指示します。 この例では、HMAC SHA-256 アルゴリズムを使用して JWT に署名するため、署名に使用する対称キーを格納する JSON Web キーをconf/api_secret.jwkに作成する必要があります。 ファイルはJSON Web Key 仕様で説明されている形式に従う必要があります。例は次のようになります。

{"keys":
[{
"k":"ZmFudGFzdGljand0",
"kty":"oct",
"kid":"0001"
}]
}

対称キーはkフィールドで定義されており、プレーンテキスト文字列fantasticjwtBase64URL エンコードされた値がここにあります。 次のコマンドを実行してエンコードされた値を取得しました。

$ echo -n fantasticjwt | base64 | tr '+/' '-_' | tr -d '='

ktyフィールドは、キー タイプを対称キー (オクテット シーケンス) として定義します。 最後に、 kid (Key ID)フィールドは、このJSON Web Keyのシリアル番号を定義します。0001これにより、同じファイル ( auth_jwt_key_fileディレクティブで名前が付けられる) 内で複数のキーをサポートし、それらのキーとそれらで署名された JWT のライフサイクルを管理できるようになります。

これで、API クライアントに JWT を発行する準備が整いました。

API クライアントへの JWT の発行

サンプル API クライアントとして、「見積システム」アプリケーションを使用し、API クライアント用の JWT を作成します。 まず、JWT ヘッダーを定義します。

{
"typ":"JWT",
"alg":"HS256",
"kid":"0001"
}

typフィールドはタイプを JSON Web Token として定義し、 algフィールドは JWT が HMAC SHA256 アルゴリズムで署名されることを指定し、 kidフィールドは JWT がそのシリアル番号を持つ JSON Web キーで署名されることを指定します。

次に、JWT ペイロードを定義します。

{
"name":"見積システム",
"sub":"quotes",
"iss":"私の API ゲートウェイ"
}

sub (件名) フィールドは、 nameフィールドの完全な値に対する一意の識別子です。 issフィールドは JWT の発行者を表します。これは、API ゲートウェイがサードパーティの発行者または集中型 ID 管理システムからの JWT も受け入れる場合に役立ちます。

JWT を作成するために必要なものがすべて揃ったので、次の手順に従って JWT を正しくエンコードして署名します。 コマンドとエンコードされた値は、読みやすくするために複数行で表示されます。実際には、それぞれが 1 行で入力または表示されます。

  1. ヘッダーとペイロードを別々にフラット化し、Base64URL エンコードします。

     

    $ echo -n '{"typ":"JWT","alg":"HS256","kid":"0001"}' | base64 | tr '+/' '-_' | tr -d '=' eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ $ echo -n '{"name":"Quotation System","sub":"quotes","iss":"My API Gateway"}' | base64 | tr '+/' '-_' | tr -d '=' eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsImlzcyI6Ik 15IEFQSSBHYXRld2F5In0
    
  2. エンコードされたヘッダーとペイロードをピリオド (.) で連結し、その結果をHEADER_PAYLOAD変数に割り当てます。

    $ HEADER_PAYLOAD=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ.eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsIm lzcyI6Ik15IEFQSSBHYXRld2F5In0
    
  3. 対称キーを使用してヘッダーとペイロードに署名し、署名を Base64URL エンコードします。

    $ echo -n $HEADER_PAYLOAD | openssl dgst -binary -sha256 -hmac fantasticjwt | base64 | tr '+/' '-_' | tr -d '=' ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I
    
  4. エンコードされた署名をヘッダーとペイロードに追加します。

    $ echo $HEADER_PAYLOAD.ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I > quotes.jwt
    
  5. API ゲートウェイに認証されたリクエストを送信してテストします (この例では、ゲートウェイは localhost 上で実行されています)。

    $ curl -H "認証: ベアラー `cat quotes.jwt`" http://localhost/products/widget1
    

ステップ 5 のcurlコマンドは、NGINX Plus がデフォルトで期待するBearer Tokenの形式で JWT を NGINX Plus に送信します。 NGINX Plus は、Cookie またはクエリ文字列パラメータから JWT を取得することもできます。これを設定するには、 auth_jwtディレクティブにtoken=パラメータを含めます。 たとえば、次の構成では、NGINX Plus はこのcurlコマンドで送信された JWT を検証できます。

$ curl http://localhost/products/widget1?apijwt=`cat quotes.jwt`
server { listen 80; location /products/ { auth_jwt "Products API" token=$arg_apijwt ; auth_jwt_key_file conf/api_secret.jwk; proxy_pass http://api_server; } }

NGINX Plus を設定し、上記のように JWT を生成して検証したら、JWT を API クライアント開発者に送信し、各 API リクエストで JWT を送信するために使用されるメカニズムについて合意する準備が整います。

ログ記録とレート制限のための JWT クレームの活用

認証資格情報としての JWT の主な利点の 1 つは、JWT とそのペイロードに関連付けられたエンティティ (発行者、発行先のユーザー、対象受信者など) を表す「クレーム」を伝達できることです。 JWT を検証した後、NGINX Plus はヘッダーとペイロードに存在するすべてのフィールドに変数としてアクセスできるようになります。 これらにアクセスするには、目的のフィールドに$jwt_header_または$jwt_claim_ をプレフィックスとして付けます (たとえば、サブクレームの場合は$jwt_claim_sub )。 つまり、API 自体に JWT 処理を実装する必要なく、JWT 内に含まれる情報を API エンドポイントに非常に簡単にプロキシできるということです。

この構成例では、いくつかの高度な機能を示します。

log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" ' '$jwt_header_alg $jwt_claim_sub' ; limit_req_zone $jwt_claim_sub zone=10rps_per_client:1m rate=10r/s; server { listen 80; location /products/ { auth_jwt "製品 API"; auth_jwt_key_file conf/api_secret.jwk; limit_req zone=10rps_per_client; proxy_pass http://api_server; proxy_set_header API-Client $jwt_claim_sub; access_log /var/log/nginx/access_jwt.log jwt; } }

log_formatディレクティブは、共通ログ形式を 2 つの追加フィールド$jwt_header_alg$jwt_claim_subで拡張するjwtと呼ばれる新しい形式を定義します。 locationブロック内では、 access_logディレクティブを使用して、検証された JWT から取得した値を含むログを書き込みます。

この例では、クレームベースの変数を使用して、IP アドレスごとではなく、API クライアントごとに API レート制限を提供しています。 これは、複数の API クライアントが単一のポータルに埋め込まれており、IP アドレスで区別できない場合に特に便利です。 limit_req_zoneディレクティブは、レート制限を計算するためのキーとして JWTサブクレームを使用し、その後、 limit_reqディレクティブを含めることで、ロケーションブロックにレート制限を適用します。

最後に、リクエストが API エンドポイントにプロキシされるときに、JWT サブジェクトを新しい HTTP ヘッダーとして提供します。 proxy_set_headerディレクティブは、API エンドポイントが簡単に使用できるAPI‑Clientという HTTP ヘッダーを追加します。 したがって、API エンドポイントは JWT 処理ロジックを実装する必要はありません。 API エンドポイントの数が増えるにつれて、これはますます価値が高まります。

JWTの取り消し

場合によっては、API クライアントの JWT を取り消したり再発行したりする必要が生じることがあります。 シンプルなマップブロックとauth_jwt_requireディレクティブを組み合わせることで、JWT の有効期限 ( expクレームで表されます) に達するまで JWT を無効としてマークし、その時点でその JWT のマップエントリを安全に削除することで、API クライアントへのアクセスを拒否できます。

この例では、 $jwt_status変数を次のように設定しています。0または1トークン内のサブクレームの値( $jwt_claim_sub変数でキャプチャされたもの)に応じて異なります。 次に、 locationブロックでauth_jwt_requireディレクティブを使用して、トークンをさらに検証 (または拒否) します。 有効であるためには、 $jwt_ステータス 変数は空ではなく、等しくない 0 (ゼロ)

map $jwt_claim_sub $jwt_status { "quotes" 0; "test" 0; default 1; } server { listen 80; location /products/ { auth_jwt "Products API"; auth_jwt_key_file conf/api_secret.jwk; auth_jwt_require $jwt_status; proxy_pass http://api_server; } }

まとめ

JSON Web Token は、API への認証されたアクセスを提供するのに適しています。 API クライアント開発者にとって、これらは従来の API キーと同様に簡単に扱うことができ、データベース検索を必要とする ID 情報を API ゲートウェイに提供します。 NGINX Plus は、JWT 自体に含まれる情報に基づいて、JWT 認証と高度な構成ソリューションをサポートします。 NGINX Plus を他のAPI ゲートウェイ機能と組み合わせることで、速度、信頼性、拡張性、セキュリティを備えた API ベースのサービスを提供できるようになります。

NGINX Plus で JWT を試すには、今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、ユースケースについてご相談ください


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"