OAuth 2.0 (Authorization code grant) で保護したAPIをAzure API Managementで公開する

このエントリは2019/09/27現在の情報に基づいています。将来の機能追加・変更に伴い、記載内容との乖離が発生する可能性があります。

シナリオ

今回考えているユースケースは以下の通り。

  • アプリがOAuth 2.0の認可コードフローに従い、OAuth 2.0プロバイダーであるAzure ADにOAuth 2.0 tokenを取得しにいく
  • 取得したOAuth 2.0 tokenを使ってAPIを呼び出す
  • APIをホストしているGatewayは、API呼び出し時に送信されたOAuth 2.0 tokenを検証する
  • 検証の結果問題なければ、バックエンドサービスへリクエストを流し、アプリはレスポンスを受け取る

なお、バックエンドサービス自体はOAuth 2.0 tokenを受け付けないものとする。

実はこのシナリオ自体は以下のドキュメントに記載があるが、日本語版では一部記述が古く、そして英語版でも記述に間違いがあるように見えるため、このエントリを備忘録として記載しておく。

Azure Active Directory と API Management で OAuth 2.0 を使用して API を保護する / Protect an API by using OAuth 2.0 with Azure Active Directory and API Management
https://docs.microsoft.com/azure/api-management/api-management-howto-protect-backend-with-aad

検証目的のため、今回はAPIを呼び出すアプリ(API Client)としてDeveloper Portalを、APIはAPIMにデフォルトで存在するEcho APIを使う。

まずは…

Azure API Management (以下APIM) インスタンスの作成

APIMインスタンスを作成する。SKUは問わない。インスタンス作成完了までに時間がかかる。

Azure ADでの設定

API を表すアプリケーションを Azure ADに登録

インスタンス生成後、APIMでホストするAPIをアプリケーションとしてAzure ADに登録する(サービスプリンシパルを作成する)。Azure CLIなどでも作成できるが、今回はAzure Portalを使って作成する。

Azure AD > 管理 > アプリの登録 で [新規登録] をクリックし、名前、サポートされているアカウントの種類を指定。リダイレクトURLは不要。

APIの公開

APIとかアプリケーションとか用語が統一されていないために困惑するが、このAPIは先ほど作成したアプリケーション、つまり今回はEcho APIというAPIを表すアプリケーションを公開する、というもの。

まず、このアプリケーションに対して利用許可を設定するために、アプリケーション ID の URIを作成する必要がある。作成したアプリケーションの概要で、[アプリケーション ID URI の追加]クリック、もしくは 管理 > APIの公開 をクリックする。

開いた画面で、[アプリケーション ID の URI]の右にある[設定]をクリックして、URIを取得する。その上で、スコープを追加する。今回、スコープはtest、同意できるユーザーは管理者のみとしておく。作成したスコープ(api://xxxxx/test)は後で利用するのでメモしておく。

APIを表すアプリケーションに対する設定はこれで終了。

API Clientを表すアプリケーションを Azure ADに登録

API Client(ここではDeveloper Portal)をOAuth 2.0クライアントとしてアプリケーションを登録する。アプリケーションの登録自体はAPIの場合と同じ。リダイレクトURIは、APIMポータルのサインインURL(https://{APIM Instance Name}.portal.azure-api.net/signin)もしくは、新しいDeveloper PortalのサインインURL(https://{APIM Instance Name}.developer.azure-api.net/signin)を指定する(後から設定することも可能)。

このタイミングで、OAuth 2.0のエンドポイントを確認、メモしておく。登録したアプリケーションの概要で[エンドポイント]をクリックする。

右から出てくる画面でOAuth 2.0認可サーバー作成時に必要なURLが表示されるので、以下のURLをメモしておく。なお、今回はV2を利用する。

これらのURLは以下のような構造になっている。

URL
認可URL
Authorization URL
https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/authorize
トークンエンドポイント
Token endpoint
https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/token
OpenID Connectメタデータ ドキュメントhttps://login.microsoftonline.com/{tenantid}/v2.0/.well-known/openid-configuration

クライアントシークレットの作成

API ClientからAPI(を表すアプリケーション)へのアクセスに必要なOAuth 2.0トークンを取得するためには、クライアントシークレットが必要である。

クライアントシークレットは、API Clientを表すアプリケーションとして登録したアプリをクリックし、管理 > 証明書とシークレット をクリック、 [新しいクライアント シークレットの追加] をクリックして、説明と有効期限を指定する(説明はオプション)。今回は無期限にしておく。画面が戻ると、値の場所にランダムな文字が入っている。これがクライアントシークレットである。この値は後から取得できないので、この時点でメモしておく。

詳細は以下のドキュメントを参照。

クライアント アプリケーションを表す別のアプリケーションを Azure AD に登録する / Register another application in Azure AD to represent a client application
https://docs.microsoft.com/azure/api-management/api-management-howto-protect-backend-with-aad#register-another-application-in-azure-ad-to-represent-a-client-application

アプリケーションの許可

API Clientに対し、先ほど公開したAPI(を表すアプリケーション)へのアクセス許可を設定する。Azure AD > 管理 > アプリの登録をクリックしてAPI Clientを表すアプリケーションを選択し、管理 > API のアクセス許可 を開いて、[+アクセス許可の追加]をクリックする。

[アクセス許可の要求]が右側から出てくるので、[自分のAPI]タブを選択し、先ほど公開したアプリケーション(下図ではLogico API)を選択する。

画面が切り替わるので、ここでアクセス許可を追加したいスコープを選択して[アクセス許可の追加]をクリックする。

ここまででAzure ADでの設定はひとまず完了(実はあと1個だけ設定しなければならない)。

APIMでの設定

APIMでOAuth2認可サーバーを構成

OAuth 2.0認可サーバーをAPIMに追加する。セキュリティ > OAuth 2.0 を選択し、 [+追加] をクリックして必要事項を入力する。クライアント登録URLが必須になっているが、これはひとまずhttps://localhost/ としておく(必須になっていること自体どうなの、というツッコミは置いておく)。

その他の設定項目は以下の通り。記載されていない設定項目はデフォルトでよい。指定後、[作成]をクリック。

設定項目
承認許可の種類承認コード(Authorization Code)
承認エンドポイントのURL先ほどメモした値
承認要求方法POSTも選択
トークンエンドポイントのURL先ほどメモした値
アクセストークンの送信方法
>既定のスコープ
API(を表すアプリケーション)で作成したスコープの値
(今回の場合、api://xxxxx/test)
クライアントの資格情報API Clientを表すアプリケーション作成時に取得したクライアントIDとクライアントシークレット

作成完了すると、OAuth 2.0の認可フローで使われるリダイレクトURIが生成されるので、再度Azure AD > アプリの登録 > API Clientを表すアプリケーション を選択し、生成されたリダイレクトURIをリダイレクトURIに設定しておく。種類はWebでOK。

OAuth 2.0認可を使うようにAPIを構成する

今回は既存のEcho APIを使う。簡単のために、APIはサブスクライブしていなくても呼び出せるようにしておく(もちろんAPI Keyを有効化しておいてもかまわない)。

APIMの画面でAPI Management > API で構成したいAPI(今回の例ではEcho API)を選択し、Settingsタブをクリックする。下にスクロールするとSecurityの項目があるので、そこでOAuth 2.0を選択し、OAuth 2.0 Serverを先ほど作成したもの(今回の例ではOAuth2)を選択して [Save] をクリックし、設定を保存する。

validate-jwt ポリシーをAPIに追加する

続いて、validate-jwt ポリシーをAPIのInbound側に設定する。validate-jwt ポリシーの詳細は以下のドキュメントを参照。

JWT を検証する / Validate JWT
https://docs.microsoft.com/azure/api-management/api-management-access-restriction-policies#ValidateJWT

Designタブに移動し、All operationsを選択して、Inbound processingで[+Add policy]をクリックし、Validate JWTをクリックする。フォーム形式の画面が現れるので、Fullをクリックして構成していく。

設定内容は以下の通り。なお、記載のないものはデフォルト設定のまま。

(注意点)Issuerは本来なら設定する必要がないのだが、取得したOAuth 2.0トークンを調べた限り、APIMが期待しているIssuerと異なるため、今回はこのIssuerを追加している。

設定項目
Header nameAuthorization
Failed validation error message認証が失敗しました。アクセストークンがないか、適切ではありません。
Issuershttps://sts.windows.net/{tenant id}/
Required claims > Nameaud
Required claims > Valuesアプリケーション ID の URI
Open ID URLs先ほどメモしたOpen ID Connect メタデータ ドキュメントのURL

なお、コード表示すると、以下のようなXML形式で確認できる(表示上、XML attributeごとに改行しているが、実際には1行)。

上記設定は以下の要素、属性に反映されている。

XML Element/Attribute
validate-jwt@header-nameAuthorization
validate-jwt@failed-validation-error-message認証が失敗しました。アクセストークンがないか、適切ではありません。
validate-jwt/openid-config@urlメモしたOpenID Connectメタデータ ドキュメントのURL。
validate-jwt/issuers/issuerhttps://sts.windows.net/{tenant id}/
validate-jwt/required-claims/claim@nameaud
validate-jwt/required-claims/claim/valueアプリケーション ID の URI

以上で完了。

試してみる

まずは、Developer Portalで、何も考えずにAPIを呼び出す。Access tokenをつけていないので、当然401が返ってくる。

では、続いてAccess tokenを取得し、Bearer tokenとして取得したtokenをつけて呼び出してみる。AuthorizationでOAuth 2.0を選択、同意画面で同意した上で、OAuth 2.0 tokenを取得する。

そのtokenを使って呼び出すと、問題なく200が返ってくることがわかる。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中