ブログ | NGINX

JWT と NGINX Plus を使用した認証とコンテンツベースのルーティング

NGINX-F5 水平黒タイプ RGB の一部
アラン・マーフィーのサムネイル
アラン・マーフィー
2018 年 3 月 1 日公開

NGINX Plus リリース 10 では、 JSON Web Token (JWT、「ジョッツ」と発音) を使用して Web および API サービスから認証をオフロードするサポートが導入されました。 R10 のリリース以降、新しいリリースごとに機能を強化し続けています。

NGINX Plus R14以降、NGINX Plus はネストされたクレームと配列データを含む JWT をサポートします。 API ゲートウェイ シナリオで使用する場合、NGINX Plus は JWT を使用して、バックエンド サービスおよび API 宛先への接続を要求しているクライアントを認証できます。

NGINX Plus を使用して JWT を認証し、JWT 情報に基づいてより高度な負荷分散の決定を行う基本的な構成を提供するよう求められることがあります。 最も簡単な解決策は、認証が成功した場合はサービスへのアクセスを許可し、失敗した場合は接続をブロックまたはリダイレクトすることです。

この記事のウォークスルーは、NGINX Plus を使用した JWT 認証とコンテンツ ベース ルーティングの概念実証を徹底的に行います。 最も幅広い可能性をカバーし、JWT に関する前提知識や経験の必要性を減らすために、「JWT 101」ウォークスルーを作成しました。これにより、JWT に関する事前の知識がなくても、このソリューション (例と背景付き) を展開できます。

すでに JWT の経験がある場合や、環境に JWT が既にある場合は、最初の 2 つのセクションをスキップして、提供されているNGINX Plus 構成スニペットを環境に合わせて調整し、JWT クレーム データに基づいて高度な負荷分散の決定を開始できます。

前提条件

このドキュメントでは、NGINX Plus が新規インストールされ、デフォルトの設定ファイルが次の場所にあることを前提としています。

  • nginx.conf は、
  • /etc/nginx/conf.d/default.conf

NGINX Plus のインストールと使用開始の詳細については、『 NGINX Plus 管理者ガイド』を参照してください。

すべての CLI コマンドはroot権限を前提としているため、非rootユーザーは自分の環境でsudo権限を持っている必要があります。

追加の背景情報や、NGINX Plus を使用した JWT のその他の使用例については、次のリンクを参照してください。

JWT と関連する署名キーの作成

以下の手順では、NGINX Plus を JWT クレームの基本的な処理用に構成する方法を示すために、例に固有のペイロード データを使用して JWT を最初から作成する手順を説明します。 サンプルの JWT ではなく既存の JWT を使用する場合は、「シークレット」ファイルに、JWT の作成に使用する署名キーと一致する Base64URL エンコードされた文字列が含まれていることを確認する必要があります。 おそらく、JWT ペイロード内のクレームも変更する必要があります。

注記: JWT をどのように生成する場合でも、Base64URL エンコーディングを使用する必要があります。これにより、パディング( =文字で実行) や、Base64 エンコーディングで通常使用されるその他の HTTP 非準拠の文字が正しく処理されます。 多くのツールはこれを自動的に処理しますが、手動の CLI ベースの Base64 エンコーダーと一部の JWT 作成ツールはこれを処理しません。 Base64URL エンコーディングの詳細については、Brock Allen によるbase64url エンコーディングRFC 4648を参照してください。

この例では、 jwt.ioの GUI (Base64URL エンコーディングを正しく実行) を使用して対称 HS256 JWT を作成します。 次のスクリーンショットは、以下の手順で指定された値を入力し、署名が検証された後の GUI の表示を示しています。

jwt.ioの GUI で作業し、右側のDecoded列のフィールドに示された値を確認または挿入して、HS256 JWT を生成します。

  1. HEADERフィールドに次のデフォルト値が表示されていることを確認し、必要に応じて内容を変更します。

    { "alg": 「HS256」、
    「タイプ」: 「JWT」
    }
  2. VERIFY SIGNATUREフィールドで、ボックス内の値 (デフォルトではsecret ) をnginx123に置き換えます。 (2 つの手順を逆にした場合に発生する問題を回避するために、 PAYLOADフィールドにデータを入力する前にこの変更を行います。)

  3. PAYLOADフィールドの内容を次のように置き換えます。

    { "exp": 1545091200,
    「名前」: 「新しいユーザーを作成」、
    「sub」: 「cuser」、
    「gname」: 「wheel」、
    「guid」: 「10」、
    「フルネーム」: "John Doe"、"uname": "jdoe"、"uid": "222",
    "sudo": true,
    "dept": "IT",
    "url": "http://secure.example.com"
    }

    注記: expクレームは JWT の有効期限と時刻を設定し、それを UNIX エポック時間 ( 1970 年 1 月 1 日の午前 0 時 UTC からの秒数) として表します。 サンプル値は、2018 年 12 月 18 日の午前 0 時 (UTC) を表します。 有効期限を調整するには、エポックタイムを変更します。

  4. フィールドの下のバーが青色で、 「署名が検証されました」と表示されていることを確認します。

  5. 左側の「エンコード」列の値をファイルまたはバッファにコピーします。 これは、ユーザーjdoe がhttp://secure.example.comにアクセスするために提示する必要がある JWT の全文であり、以下のテストで使用します。 ここでは表示上の都合上、JWT を改行して表示していますが、NGINX Plus には単一行の文字列として提示する必要があります。

    eyJhbGciOiJIUzI1NiIsinR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUWOTEYMDASIm5hbWUiOi
    JDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkI
    ジョイMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIy
    いいえ
    LLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4

NGINX Plus ホストで作業し、次の手順に従って、NGINX Plus がnginx123で署名された JWT を検証するために使用するキー ファイルを作成します。

  1. このコマンドを実行すると、署名文字列に対応する Base64URL エンコードされた文字列が生成されます。 ( trコマンドは、Base64URL エンコードに必要な文字の置換を行います。)

    # echo -n nginx123 | base64 | tr '+/' '-_' | tr -d '=' bmdpbngxMjM
  2. /etc/nginx/ディレクトリに、NGINX Plus が JWT 署名を検証するために使用するapi_secret.jwkというキー ファイルを作成します。 以下の内容を挿入してください。 kフィールドの値は、前の手順で生成したnginx123の Base64URL エンコード形式です。

    {"キー": [{
    "k":"bmdpbngxMjM",
    "kty":"oct"
    }]
    }

JWT を処理するための NGINX Plus の設定

このセクションの手順では、リクエストに含まれる JWT を検証し、クライアントが承認されている場合は保護されたリソースを表示するように NGINX Plus を構成します (承認されていないクライアントに表示されるデフォルトのページではなく)。 また、JWT 関連情報をキャプチャする新しいログ形式も定義します。

JWT検証とコンテンツベースのルーティングの設定

これらの手順では、NGINX Plus が読み取らないようにdefault.conf設定ファイルの名前を変更し、テスト専用の新しい設定を作成するという標準的なベスト プラクティスに従います。 これにより、テストが完了したときやテスト中に問題が発生した場合に、簡単にデフォルト構成を復元できます。

  1. default.conf の名前を変更します:

    # mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
  2. /etc/nginx/conf.d/に、次の内容を含むjwt-test.confという新しい設定ファイルを作成します。 JWT 固有のログ記録、JWT 検証、コンテンツベースのルーティングを構成します (完全な分析はスニペットの後に続きます)。

    server {
    listen 80;
    access_log /var/log/nginx/host.access.log jwt;
    
    location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    
    # JWT 検証
    auth_jwt "JWT テスト領域" token=$arg_myjwt;
    auth_jwt_key_file /etc/nginx/api_secret.jwk;
    error_log /var/log/nginx/host.jwt.error.log debug;
    
    if ( $jwt_claim_uid = 222 ) {
    add_header X-jwt-claim-uid "$jwt_claim_uid" always;
    add_header X-jwt-status "$jwt_claim_url にリダイレクト" always;
    return 301 $jwt_claim_url;
    }
    
    if ( $jwt_claim_uid != 222 ) {
    add_header X-jwt-claim-uid "$jwt_claim_uid" always;
    add_header X-jwt-status "無効なユーザー、リダイレクトなし" always;
    }
    }
    }

locationブロック内のディレクティブは、NGINX Plus に JWT を含む HTTP リクエストを処理する方法を指示します。 ( access_logディレクティブによって定義されるログ設定の詳細については、次のセクションを参照してください。) NGINX Plus は次の手順を実行します。

  1. リクエスト文字列のmyjwt引数から JWT を抽出します ( auth_jwtディレクティブのtoken引数で指定)。

  2. auth_jwt_key-fileディレクティブで指定された署名キー (ここではapi_secret.jwk ) を使用して JWT をデコードします。 ペイロードに対して次のように動作します (これらのアクションは JWT 処理に固有のものであり、対応する NGINX Plus ディレクティブはありません)。

    • JWT の有効期限が切れていないこと、つまりペイロード内のexpクレームで指定された有効期限が過去ではないことを確認します。
    • ペイロード内の各クレームに対してキーと値のペアを作成します。 キー名は、 $ jwt_claim_claim-nameという形式の変数です (たとえば、 uidクレームの場合は$jwt_claim_uid )。
  3. すべてのエラーをデバッグレベルで/var/log/nginx/host.jwt.error.logに記録します。

  4. $jwt_claim_uidの値が222(2 つのifディレクティブで指定されているとおり) 適切な応答をクライアントに送信します。 これは、JWT 内の情報を使用してコンテンツ ベースのルーティングを実行する方法です。

    • 値が222NGINX Plus は、クライアント ( returnディレクティブ) を JWt のurlクレームで指定された URL にリダイレクトする応答を送信します。 デバッグの目的で、応答に 2 つのヘッダー ( add_headerディレクティブ) を追加します。最初のヘッダーはuidクレームの値をキャプチャし、2 番目のヘッダーはクライアントがリダイレクトされたという事実を記録します。
    • 値が222NGINX Plus は、デフォルトのインデックス ページ (同じロケーションブロック内のroot ディレクティブindexディレクティブによって定義される) を提供します。 再度デバッグの目的で、 uidクレームの値をキャプチャし、クライアントが JWT で指定された URL にアクセスできなかったという事実を記録するヘッダーを追加します。

    注記: 変数を評価するためにifディレクティブを使用することは、一般的にベストプラクティスとは見なされておらず、代わりにmapディレクティブを使用することをお勧めします。 ただし、この単純な例では、 ifディレクティブは意図したとおりに機能します。

実際には、この構成により、保護されたリソースへのアクセスは許可されたユーザーのみに提供されます。 つまり、有効な JWT を持つユーザーは JWT で指定された URL にアクセスでき、有効な JWT を持たないユーザーはデフォルトのページにアクセスできるようになります。

JWT データのログ記録

jwt-test.confaccess_logディレクティブによって参照されるjwtというログ形式を定義することで、コンテンツベース ルーティングの JWT 処理の構成を完了します。 アクセス ログに JWT データをキャプチャします。

  1. /etc/nginx/nginx.confに次のlog_formatディレクティブを追加します。

    log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
    '$jwt_header_alg $jwt_claim_uid $jwt_claim_url';

    この形式には、このチュートリアルで使用される 2 つの JWT クレーム ( uidurl ) が含まれますが、クレームに対応する変数名を使用して、任意の JWT クレーム データを$jwt_claim_ claim‑nameの形式でログに記録できます。

  2. nginx.confを保存し、次のコマンドを実行して、完全な構成 (新しいjwt-test.confファイルを含む) の構文の妥当性をテストします。 報告されたエラーを修正します。

    # nginx -t
  3. NGINX Plus をリロードします。

    # nginx -s リロード
    

構成のテスト

ブラウザやcurlなどの CLI ツールを使用して、NGINX Plus が JWT を正しく検証し、それを提示するクライアントを認証し、コンテンツベースのルーティングを実行しているかどうかをテストできます。 (認証と検証のみをテストし、コンテンツベースのルーティングはテストしない場合は、 jwt-test.conf内の 2 つのifブロックをコメント アウトします。)

テストを実行するには、リクエストURLにmyjwt引数を含め、 URLクレームが含まれるJWTの全文を提供します。222 。 ここでも、表示上の都合で改行を追加しました。

http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
JE1NDUWOTEYMDASIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
ルIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5le
GFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4

対応するcurlコマンドは次のとおりです (改行なしなので、必要に応じてコピーして貼り付けることができます)。

# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Y YQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4

JWTのuidクレームの値は222、NGINX Plus が制限されたページhttp://secure.example.comの内容を表示することが期待されます。

ここで、JWTのURLクレームが222NGINX Plus は制限されたページの内容を表示せず、代わりにローカル サーバーのindex.htmlページ (この場合はhttp://example.com/index.html)を表示します。

まず、 jwt.ioで別のJWTを生成します。uidクレームは222; 例として、111 。 JWT を含むリクエスト URL は次のとおりです。

http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
JE1NDUWOTEYMDASIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
翻訳: ...
eGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg

curlコマンドは次のとおりです。

# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg

この場合、NGINX Plus がhttp://example.com/index.htmlを提供することを期待します。

どちらのテスト条件でも、ヘッダー検査ツール ( curlや一部のブラウザに付属する開発者ツールなど) を使用して、新しいヘッダーX-jwt-claim-uidX-jwt-status がレスポンスに追加されたことを確認できます。

テスト中に問題が発生した場合は、 /var/log/nginx/host.jwt*のアクセス ログとエラー ログを確認してください。 特にエラー ログには、検証や検証ファイルへのアクセスなどの問題が表示されます。

JWT を Cookie で渡す

基本的な例では、NGINX Plus はリクエスト URL のmyjwt引数から JWT を抽出します。 NGINX Plus は、Cookie で JWT を渡すこともサポートしています (詳細については、 NGINX JWTリファレンス ドキュメントを参照してください)。 jwt-test.confで、 auth_jwtディレクティブを変更して、トークンパラメータの最初の要素が$argではなく$cookieになるようにします。

auth_jwt "JWT テスト領域" token=$cookie_myjwt;

myjwtという Cookie で JWT を提供するには、適切なcurlコマンドは次のようになります。

# curl -v --cookie myjwt= JWT テキストexample.com/index.html

JWT を使用したコンテンツ ベース ルーティングを実際にお試しください。今すぐ NGINX の30 日間無料トライアルを開始するか、弊社にお問い合わせの上、ユースケースについてご相談ください


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