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

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

はじめに

先日動作確認したAuthorization Codeを踏まえて、Client credentials grantでの設定と動作を確認する。

なお、バックエンドサービス自体は以前と同様、OAuth 2.0 tokenを受け付けないものとする。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は不要。

アプリケーション ID の URIを作成

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

開いた画面で、[アプリケーション ID の URI]の右にある[設定]をクリックして、URIを取得する。

APIのアクセス許可

RBACを使ったClient credentials grantの利用の場合、Authorization code grantの場合のようなDelegated permission(委任済みの許可)ではなく、Application permission(アプリケーションの許可)を構成する必要があり、今回の場合、アプリケーションロールを作成する必要がある。そのため、APIを表すアプリケーションで 管理 > マニフェスト を選択し、appRolesに以下のコードを追加する。

"appRoles": [
    {
        "allowedMemberTypes": [
            "Application"
        ],
        "description": "[API のアクセス許可]で表示される説明",
        "displayName": "[API のアクセス許可]で表示される表示名",
        "id": "[guid]",
        "isEnabled": true,
        "value": "API.Request"
    }
]

上記JSONの各要素の意味は以下の通り。

要素意味
allowedMemberTypes割り当てたいロールの対象。UserもしくはApplication、その両方を指定できる
description[API のアクセス許可]で表示される説明
displayName[API のアクセス許可]で表示される表示名
idこのロールに割り当てるguid。PowerShellやCloud Shellで生成したものを貼り付ける。以下はPowerShell/Cloud Shellの例
[guid]::NewGuid()
isEnabled有効化するか否か。当然true
value[APIのアクセス許可]でスコープとして見えるもの。Authorization code grantで作成したスコープと同じ。

アプリケーションのマニフェストとアプリケーションロールの設定方法は以下のドキュメントを参照。

Azure Active Directory のアプリ マニフェスト / Azure Active Directory app manifest
https://docs.microsoft.com/azure/active-directory/develop/reference-app-manifest
方法:アプリケーションにアプリ ロールを追加してトークンで受け取る / How to: Add app roles in your application and receive them in the token
https://docs.microsoft.com/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
Microsoft ID プラットフォームと OAuth 2.0 クライアント資格情報フロー / Microsoft identity platform and the OAuth 2.0 client credentials flow
https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow

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

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

API Client(今回はREST Client)をOAuth2クライアントとしてアプリケーションを登録する。アプリケーションの登録自体はAPIの場合と同じ。リダイレクトURIは設定不要。

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

右から出てくる画面でOAuth2認可サーバー作成時に必要な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 tokenを取得するためには、クライアントシークレットが必要である。

クライアントシークレットは、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のアクセス許可

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

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

画面が切り替わるので、ここでアクセス許可を追加したいスコープを選択して[アクセス許可の追加]をクリックする。今回の場合、マニフェストに追加したAPI.Requestが確認できるので、これを選択して[アクセス許可の追加]をクリックする。

ここまででAzure ADでの設定は完了。

APIMでの設定

APIMでOAuth 2.0認可サーバーを構成

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

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

設定項目
承認許可の種類クライアントの資格情報(Client Credentials)
承認エンドポイントのURL先ほどメモした値
承認要求方法POSTも選択
トークンエンドポイントのURL先ほどメモした値
クライアントの資格情報API Clientを表すアプリケーション作成時に取得したクライアントIDとクライアントシークレット

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として先ほど作成したもの(今回の例ではlogico-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は本来なら設定する必要がないのだが、取得したOAuth2トークンを調べた限り、APIMが期待しているIssuerと異なるため、今回はこのIssuerを追加している。

設定項目
Header nameAuthorization
Failed validation error message認証が失敗しました。アクセストークンがないか、適切ではありません。
Issuershttps://sts.windows.net/{tenant id}/
Required claims > Nameaud
Required claims > Matchany
Required claims > Valuesアプリケーション ID の URIとアプリケーションID
つまり、api://xxxxxとxxxxxを2個。
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@matchany
validate-jwt/required-claims/claim/valueアプリケーション ID の URIとアプリケーションID
つまり、api://xxxxxとxxxxxを2個。

以上で完了。

試してみる

REST ClientとしてPostmanを使う。何も考えずにAPIを呼び出すとAuthorizationヘッダーにBearer tokenをつけていないので、当然401が返ってくる。

では、続いてAccess tokenを取得し、取得したtokenをBearer tokenとしてつけて呼び出す。Client credentials grantでOAuth 2.0 tokenを取得する。このとき、Scopeには以下の文字列を指定する。

{APIを表すアプリケーションID}/.default

例えばAPIを表すアプリケーションIDが6ae96d41-273e-5c15-caa4-def0053b6a26である場合、以下の値をScopeに指定する。

6ae96d41-273e-5c15-caa4-def0053b6a26/.default

取得したtokenを使って呼び出すと、問題なく200が返ってくることがわかる(200でResponseがないのは、Query Parameterを指定していないためで、この挙動自体に問題はない)。

 JWTトークンの内容を見ると、以下のよう。

コメントを残す

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

WordPress.com ロゴ

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

Facebook の写真

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

%s と連携中