HTTP リクエストを利用して Azure Active Directory からアクセストークンを発行して、APIM で JWT 検証を実行する
質問
なりすましや改ざん防止のため、JWT 検証を導入しています。デバッグのため、HTTP リクエストを利用して Azure Active Directory からクライアント資格情報フローでアクセストークンを発行して、APIM で JWT 検証を実行したいです。
回答
API Management では、OAuth 2.0 プロトコルと Azure Active Directory (Azure AD) を使用して、API を保護できます。
OAuth 2.0 承認と Azure Active Directory を使用して Azure API Management で API を保護する
OAuth 2.0 ではアクセス トークンを取得するための承認フローが定義されています。
The OAuth 2.0 Authorization Framework
各承認フローの一般的なユースケースは以下の通りです。
今回ご紹介する手順では クライアント資格情報 を使用しています。 
| 付与フロー | 説明 | ユースケース | 
|---|---|---|
| 認証コード | リソースサーバーから保護されたデータにアクセスすることをクライアントに承認するために最も使用される付与タイプです。 | ウェブサーバーのようなセキュアなクライアントから利用されます。 | 
| 暗黙的 | すべてのアプリケーションコードとストレージに簡単にアクセスできるためクライアントの秘密を守ることができないユーザーベースのクライアントを対象としています。 | モバイルアプリやシングルページアプリケーションなど、クライアントシークレット/トークンを保護できないクライアントが使用します。 | 
| クライアント資格情報 | この付与タイプは、ユーザーのコンテキスト外でアクセストークンを取得するための非対話的な方法です。 | データへのアクセスに特定のユーザーの許可を必要としないマシンツーマシン認証に適しています。 | 
| リソース所有者のパスワード資格情報 | リソース所有者(ユーザー)のユーザー名とパスワードの認証情報を使用して、リソースサーバーから保護されたデータにアクセスすることを許可するものです。 | ユーザー名とパスワードでログインする場合(ファーストパーティアプリのみ) | 
手順の概要
Azure Active Directory からクライアント資格情報フローでアクセストークンを発行して、 APIM で JWT 検証を実行するための手順の概要は以下の通りです。
- APIM インスタンスを作成
 - アプリの登録を Azure Active Directory に追加
 - APIM のポリシーを追加
 - Azure Active Directory からアクセス トークンを取得
 - クライアントから APIM に対してリクエストを実行
 
手順
APIM インスタンスを作成
まず以下の記事を参考に APIM インスタンスを作成してください。
クイック スタート」を参照してください。Azure portal を使用して新しい Azure API Management サービス インスタンスを作成する
後の手順でサンプルの API を利用するため、Developer プランで作成してください。
アプリの登録を Azure Active Directory に追加
- Azure Active Directory 画面で、[アプリの登録]>[新規登録] を選択します。
 

- [アプリケーションの登録] ページで、[名前] を入力します。
 

- 
    
[登録] を選択します。
 - 
    
アプリの登録 画面から [概要] を選択し、[アプリケーション (クライアント) ID] と [ディレクトリ (テナント) ID] をメモします。
 

- [証明書とシークレット]>[クライアント シークレット]>[クライアント シークレット]>[新しいクライアント シークレット] の順に選択します。[説明] を入力し、[追加] を選択します。
 

- [値] をメモします。
 

- 
    
[API の公開]>”アプリケーション ID URI” の横にある [設定] > クリックします。”アプリケーション ID URI” のテキスト ボックスは規定値のままにし、[保存] を選択します。
アプリケーション ID URI でアプリケーションを一意に特定できます。AAD からアクセストークンを取得するスコープを指定するために必要です。詳細は以下の記事をご参照ください。
App Service アプリに対するアプリ登録を Azure AD で作成する
スコープとアプリケーション ID URI - 
    
[アプリケーション ID URI] をメモします。
 

- [マニフェスト] を選択し、accessTokenAcceptedVersion を 2 に変更、[保存] を選択します。
リソースで想定されているアクセス トークンのバージョンを指定しています。 

APIM のポリシーを追加
- API Management サービス 画面で、[API]> 任意の API > 任意のオペレーション > </> (Policy Code Editor) の順に選択します。
 

- Policy Editor に以下のポリシーを貼り付けます。
 
<policies>
    <inbound>
        <base />
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
            <openid-config url="https://login.microsoftonline.com/[ディレクトリ (テナント) ID]/v2.0/.well-known/openid-configuration" />
            <required-claims>
                <claim name="aud">
                    <value>[アプリケーション (クライアント) ID]</value>
                </claim>
            </required-claims>
        </validate-jwt>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
- [Save] を選択します。
 
Azure Active Directory からアクセス トークンを取得
- Powershell で以下のコマンドを実行して、Azure Active Directory からアクセス トークンを取得します。
 
$tenant_id     = '[ディレクトリ (テナント) ID]'
$grant_type    = 'client_credentials'
$client_id     = '[アプリケーション (クライアント) ID]'
$client_secret = '[(クライアント シークレットの)値]'
$scope         = '[アプリケーション ID URI]/.default'
$response      = Invoke-WebRequest https://login.microsoftonline.com/$tenant_id/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "grant_type=$grant_type&client_id=$client_id&client_secret=$client_secret&scope=$scope"
$jwt_token     = ConvertFrom-Json $response.Content | Select-Object -expand "access_token"
- 取得したアクセス トークンは、以下のコマンドで確認できます。
 
$jwt_token
- JWT Decoderを利用してアクセストークンのクレームを確認できます。
 

- 各クレームの説明は以下の記事を参照してください。
アクセス トークン内のクレーム 
クライアントから APIM に対してリクエストを実行
- API Management サービス 画面で、[概要]>[ゲートウェイの URL] をメモします。
 

- API Management サービス 画面で、[サブスクリプション]>”Built-in all-access subscription”>右側の […] > [キーの表示/非表示] を選択します。[主キー] をメモします。
 

- Powershell から以下のコマンドを実行して、APIM へリクエストを送信します。
 
$gateway_url      = '[ゲートウェイの URL]'
$subscription_key = '[主キー]'
$authorization    = "Bearer " + $jwt_token
$trace            = 'True'
try {
    $response = Invoke-WebRequest $gateway_url/echo/resource?param1=sample -Headers @{'Ocp-Apim-Subscription-Key'=$subscription_key;'Authorization'=$authorization;'Ocp-Apim-Trace'=$trace}
}
catch {
    $_.Exception.Response.Headers['Ocp-Apim-Trace-Location']
}
- レスポンスの StatusCode を確認して、200 になっていれば JWT 検証が成功しています。
 
$response

- JWT 検証に失敗した場合は、401 Unauthorized が返されます。リクエストの Ocp-Apim-Trace ヘッダーを True にしていれば、レスポンスの Ocp-Apim-Trace-Location ヘッダーにリクエストのトレースが保存されます。
上記の Powershell コマンドでは、リクエストが失敗した場合に、Ocp-Apim-Trace ヘッダーが出力されます。 

- トレースには、JWT 検証失敗の原因が出力されます。
以下の例では、JWT Validation Failed: IDX10511: Signature validation failed.と出力されているのが確認できます。Authorization ヘッダーのフォーマットが不正であろうことが分かります。 

参考ドキュメント
Azure Apim Hands on Lab - Azure APIM and Oauth2
Protect API’s using OAuth 2.0 in APIM
2023 年 1 月 3 日時点の内容となります。
本記事の内容は予告なく変更される場合がございますので予めご了承ください。