このエントリは2019/09/30現在の情報に基づいています。将来の機能追加・変更に伴い、記載内容との乖離が発生する可能性があります。
シナリオ・ユースケース
先日のエントリはOAuth 2.0を使っていたが、これをOpenID Connectに置き換えた場合を検討する。ユースケースは前回のエントリと同様。先日のエントリは以下。
OAuth 2.0 (Authorization code grant) で保護したAPIをAzure API Managementで公開する
https://logico-jp.io/2019/09/30/protecting-apis-with-oauth2-authorization-code-grant-in-azure-api-management/

なお、バックエンドサービス自体はOpenID Connectのtokenを受け付けないものとする。
検証目的のため、今回はAPIを呼び出すアプリ(API Client)としてDeveloper Portalを、APIはAPIMにデフォルトで存在するEcho APIを使う。
OpenID Connectを使ったWebアプリケーションの保護は、以下のドキュメントに記載がある。APIも基本的な設定は同じ。
OpenID Connect と Azure Active Directory を使用する Web アプリケーションへのアクセスの承認 / Authorize access to web applications using OpenID Connect and Azure Active Directory
https://docs.microsoft.com/azure/active-directory/develop/v1-protocols-openid-connect-code
まずは…
Azure API Management (以下APIM) インスタンスの作成
APIMインスタンスを作成する。SKUは問わない。インスタンス作成完了までに時間がかかるのはお約束。
Azure ADでの設定
API を表すアプリケーションを Azure ADに登録
インスタンス生成後、APIMでホストするAPIをアプリケーションとしてAzure ADに登録する(サービスプリンシパルを作成する)。Azure CLIなどでも作成できるが、今回はAzure Portalを使って作成する。
Azure AD > 管理 > アプリの登録 で [新規登録] をクリックし、名前、サポートされているアカウントの種類を指定。リダイレクトURLは不要。

クライアントシークレットの作成
アプリケーションを登録後、クライアントシークレットを取得する。管理 > 証明書とシークレット をクリック、 [新しいクライアント シークレットの追加] をクリックして、説明と有効期限を指定する(説明はオプション)。今回は無期限にしておく。画面が戻ると、値の場所にランダムな文字が入っている。これがクライアントシークレットである。この値は後から取得できないので、この時点でメモしておく。
アプリケーション ID の URI の作成
このタイミングで、アプリケーション IDのURIを作成しておく。値自体はapi://{client id}ではあるが、明示的に作成が必要である。作成したアプリケーションの概要で、[アプリケーション ID URI の追加]クリック、もしくは 管理 > APIの公開 をクリックする。

開いた画面で、[アプリケーション ID の URI]の右にある[設定]をクリックして、URIを取得する。OAuth2とは異なり、スコープの作成は不要。
OpenID Connect認可サーバー構成に関係するエンドポイント
続いて、OpenID Connectに関係するエンドポイントを確認するため、登録したアプリケーションの概要で[エンドポイント]をクリックする。

右から出てくる画面でOpenID Connectメタデータ ドキュメントのURLをメモしておく。

このURLは以下のような構造になっている。
URL | |
---|---|
OpenID Connectメタデータ ドキュメント | https://login.microsoftonline.com/{tenantid}/v2.0/.well-known/openid-configuration |
APIを表すアプリケーションに対する設定はこれで終了。
APIMでの設定
APIMでOpenID Connect認可サーバーを構成
OpenID Connect認可サーバーをAPIMに追加する。セキュリティ > OpenID Connect を選択し、 [+追加] をクリックして必要事項を入力する。

設定項目は以下の通り。記載されていない設定項目はデフォルトでよい。指定後、[作成]をクリック。
設定項目 | 値 |
---|---|
表示名 | 任意 |
名前 | 任意(表示名に従って自動的に入力) |
説明 | 任意 |
メタデータ エンドポイント URL | 先ほどメモした値 |
クライアントの資格情報 | API Clientを表すアプリケーション作成時に取得したクライアントIDとクライアントシークレット |
作成完了すると、承認コードタイプ(Authorization code type、正しくは認可コード)、暗黙付与タイプ(Implicit grant type)のコールバックURLが生成されるので、それらをAzure AD > アプリの登録 > API Clientを表すアプリケーション を選択し、生成されたリダイレクトURIと、Developer PortalのURLと併せて、3個のリダイレクトURIに設定しておく。種類はWebでOK。

OpenID Connect認証を使うようにAPIを構成する
前述の通り、既存のEcho APIを使う。簡単のために、APIはサブスクライブしていなくても呼び出せるようにしておく(もちろんAPI Keyを有効化しておいてもかまわない)。
APIMの画面でAPI Management > API で構成したいAPI(今回の例ではEcho API)を選択し、Settingsタブをクリックする。下にスクロールするとSecurityの項目があるので、そこでOpenID Connectを選択し、OpenID Connect Serverとして先ほど作成したもの(今回の例ではOpenID Connect)を選択して [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をクリックして構成していく。

設定内容は以下の通り。なお、記載のないものはデフォルト設定のまま。
設定項目 | 値 |
---|---|
Header name | Authorization |
Failed validation error message | 認証が失敗しました。アクセストークンがないか、適切ではありません。 |
Required claims > Name | aud |
Required claims > Values | アプリケーション ID (APIアプリケーションのクライアントID) |
Open ID URLs | 先ほどメモしたOpen ID Connect メタデータ ドキュメントのURL |

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

上記設定は以下の要素、属性に反映されている。
XML Element/Attribute | 値 |
---|---|
validate-jwt@header-name | Authorization |
validate-jwt@failed-validation-error-message | 認証が失敗しました。アクセストークンがないか、適切ではありません。 |
validate-jwt/openid-config@url | メモしたOpenID Connectメタデータ ドキュメントのURL。 |
validate-jwt/required-claims/claim@name | aud |
validate-jwt/required-claims/claim/value | アプリケーション ID (APIアプリケーションのクライアントID) |
以上で完了。
試してみる
まずは、Developer Portalで、何も考えずにAPIを呼び出す。Access tokenをつけていないので、当然401が返ってくる。

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

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

注意
今回、Implicit Grantの構成は実施していないため、Developer PortalでImplicitを選択すると、401が返る。Implicitに対応する仕組みは将来まとめる予定。