Fusic Tech Blog

Fusion of Society, IT and Culture

Azure API ManagementとActive Directoryを連携してOAuth2認証する方法
2021/04/26

Azure API ManagementとActive Directoryを連携してOAuth2認証する方法

以下の記事でRailsアプリのユーザー認証をAzure ADと連携させました。

Railsアプリのユーザ認証をAzure ADと連携する

Webシステムの認証はこれでOKですが、API Managementを使ってエンドユーザにAPIを公開している場合、APIの認証もADと連携させたいところです。

本記事では具体的な設定方法をまとめます。

記事を書いた理由

基本的には以下ドキュメントを参考に進めていけば、API ManagementにOAuth2認証を追加できます。

Azure AD で OAuth 2.0 認証を使用して、Azure API Management で Web API バックエンドを保護する

しかし、ドキュメントに記載されている手順が多く、またある程度Azureを知っている前提で記載されていることから、私にとっては難易度が非常に高かったです。

今後、同じような手順を踏む方々、Azure初心者の方々でも完走できるよう、より詳細な手順を記載します。

手順の概要

以下のような手順でOAuth2認証に対応したAPIを作成します。

  1. Azure Learnを参考にAPIを作成する
  2. Azureのドキュメントを参考に認証を追加する

    1. APIを表すApp(backend-app)を作成
    2. クライアントを表すApp(client-app)を作成
    3. Azure ADでclient-appがbackend-appを呼び出せるようアクセス許可
    4. APIにOAuth2認証を追加
    5. APIにアクセス制限ポリシーを設定
    6. Developer portalを使ってテスト

手順を進めるごとに様々なリソースを作成するので、リソース同士がどのように関連しているのかわからなくなります。最終的には以下のようなリソース構成を目指していることを頭においた上で、読み進めてください。

なお、画面の表記に関する記載は混乱を避けるため「英語」で統一します。ご了承ください。

Azure Learnを参考にAPIを作成する

まずはOAuth2認証がない通常の(サブスクリプションキー認証の)APIを作成します。この手順については、次のチュートリアルがわかりやすくまとめられているのでこの手順通りに進めてください。

Azure API Management を使用して、複数の Azure Functions アプリを一貫した API として公開する

注意すべきポイントを列挙します。

アカウントによってはSandbox環境が使えないことがあるようです。

一方、ローカルPCからだとデプロイに失敗することがあります。

Azure PortalからCloud Shellを開き、ここで実行すると確実です。

既にResource Groupが存在するアカウントを利用すると、思わぬResource Groupにデプロイされる

このチュートリアルで利用するsetup.shは、既に存在するResource Groupのうち最初のResource Groupにデプロイしようとします。以下のように修正することで、指定したResource Groupにデプロイすることができます。

diff --git a/setup.sh b/setup.sh
index e3e203a..81c2fb2 100644
--- a/setup.sh
+++ b/setup.sh
@@ -6,8 +6,8 @@ export PRODUCT_FUNCTION_NAME=ProductFunction$(openssl rand -hex 5)
 export ORDER_FUNCTION_NAME=OrderFunction$(openssl rand -hex 5)

 # Get the resource group and location
-export RESOURCE_GROUP=$(az group list --query "[0].name" -o tsv)
-export LOCATION=$(az group show --name $RESOURCE_GROUP | jq -r ".location")
+export RESOURCE_GROUP=apimanagement
+export LOCATION=japaneast
 printf "\nThe resource group is called $RESOURCE_GROUP and is located in $LOCATION\n"

API Managementの初回デプロイに時間がかかる

チュートリアルには「30分程度かかる可能性がある」と記載されていますが、私の環境だと45分ほどかかりました。気長に待ちましょう。

APIを表すApp(backend-app)を作成

本家のドキュメントのこの部分に相当する手順です。

Azure PortalにてActive Directory→App registrations→New registrationの順でクリックします。

以下の通り入力して「Register」をクリックしてください。

  • Name: backend-app
  • Supported account types: Accounts in this organizational directory only (xxx only - Single tenant)
  • Redirect URI: Webを選択、URIは空

Azure PortalにてActive Directory→App registrations→backend-appの順でクリックします。

Application (client) ID の値をメモしておきましょう。

そのまま、Expose an API→Setをクリックします。

デフォルトの値のまま、Saveをクリックします。

+Add a scope をクリックします。

以下の通り入力して「Add scope」をクリックしてください。

  • Scope name: products
  • Who can coonsent?: Admins only
  • Admin consent display name: products
  • Admin consent description: products
  • State: Enabled

Scopeが作成できたら、ScopeのURLをメモしておきましょう。

クライアントを表すApp(client-app)を作成

本家のドキュメントのこの部分に相当する手順です。

Azure PortalにてActive Directory→App registrations→New registrationの順でクリックします。

以下の通り入力して「Register」をクリックしてください。

  • Name: client-app
  • Supported account types: Accounts in this organizational directory only (xxx only - Single tenant)
  • Redirect URI: Webを選択、URIは空

Azure PortalにてActive Directory→App registrations→client-appの順でクリックします。

Application (client) ID の値をメモしておきましょう。

そのままCertificates & secrets→+New client secret→Addをクリックします。

出来上がったClient secretの Value をメモしておきましょう。

Azure ADでclient-appがbackend-appを呼び出せるようアクセス許可

本家のドキュメントのこの部分に相当する手順です。

Azure PortalにてActive Directory→App registrations→client-app→API permissions→+Add a permissionの順でクリックします。

My APIs→backend-appの順でクリックします。

Permissionsにてproductsを選択し、Add permissionsをクリックします。

Grant admin consent for xxxをクリックします。ここは全体管理者と特権ロール管理者、および一部のアプリケーションでは、アプリケーション管理者とクラウド アプリケーション管理者のいずれかが付与されたADユーザーでないとクリックできないので注意が必要です。

APIにOAuth2認証を追加

本家のドキュメントのこの部分に相当する手順です。

OAuth2認証に使用するエンドポイントを確認する

Azure PortalにてActive Directory→App registrations→Endpointsをクリックします。

Authorization EndpointおよびToken Endpointをそれぞれメモします。

API ManagementにOAuth2認証を設定する

Azure PortalにてAPI Management services→(Azure Learnの手順に沿って作成したインスタンス)→OAuth 2.0 + OpenID Connect→OAuth 2.0→+Addをクリックします。

以下の通り入力してください。この時、「Create」はまだクリックしないようにしましょう。

  • Display name: oauth2
  • Client registration page URL: http://localhost
  • Authorization grant types: Authorization code
  • Authorization endpoint URL: (先の手順でメモしたAuthorization Endpoint)
  • Authorization request method: GET, POST
  • Token endpoint URL: (先の手順でメモしたToken Endpoint)
  • Default scope: (先の手順でメモしたScopeのURL)
  • Client ID: (先の手順でメモしたclient-appのClient ID)
  • Client Secret: (先の手順でメモしたclient-appのClient Secret)

入力が完了したら、Redirect URIをメモして、Createをクリックします。

client-appにリダイレクトURIを紐付ける

Azure PortalにてActive Directory→App registrations→client-app→Authentication→Platform configurations→+Add a platformの順にクリックします。

Webを選択します。

先の手順でメモしたRedirect URIを入力し、Configureをクリックします。

APIでOAuth2認証を使用するよう設定する

Azure PortalにてAPI Management services→(Azure Learnの手順に沿って作成したインスタンス)→APIs→(Azure Learnの手順に沿って作成したProductsのAPI)→Settingsの順にクリックします。

SecurityのUser authorizationを「OAuth 2.0」とし、OAuth 2.0 serverを「oauth2」とします。 

APIにタグを付与する

前の手順に引き続きSettingsタブにて以下のようなタグを付与します。

  1. Products: Starter および Unlimited
  2. Gateways: Managed

APIにアクセス制限ポリシーを設定

本家のドキュメントのこの部分に相当する手順です。

Azure PortalにてAPI Management services→(Azure Learnの手順に沿って作成したインスタンス)→APIs→(Azure Learnの手順に沿って作成したProductsのAPI)→Design→ProductDetails→</>の順にクリックします。

アクセス制限ポリシーを以下の通り修正します。

<policies>
    <inbound>
        <base />
        <set-backend-service id="apim-generated-policy" backend-id="productfunction20ca1248af" />
        <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/common/v2.0/.well-known/openid-configuration" />
            <required-claims>
                <claim name="aud">
                    <value>(backend-appのアプリケーションID)</value>
                </claim>
            </required-claims>
        </validate-jwt>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Developer portalを使ってテスト

本家のドキュメントのこの部分に相当する手順です。

Developer portalを有効化する

Azure PortalにてAPI Management services→(Azure Learnの手順に沿って作成したインスタンス)→Portal overviewをクリックします。

次の順にクリックします。

  1. Enable Azure AD
  2. Enable CORS
  3. Publish

Developer portalをクリックし、開いた画面のURLをメモします。

ブラウザのシークレットウインドウを開いて、メモしたURLにアクセスします。

APIのサブスクリプションキーを確認する

Azure PortalにてAPI Management services→(Azure Learnの手順に沿って作成したインスタンス)→Subscriptions→+Add subscriptionをクリックします。

Nameに任意の名前を入力しSaveをクリックします。

作成したキーの右側の「・・・」をクリックしShow/hide keysをクリックすることでPrimary Keyを表示→メモします。

テスト

Developer portalにてAPIs→(Azure Learnの手順に沿って作成したAPI名)をクリックします。

GET ProductDetails→Try itの順でクリックします。

次のように入力します。

  • Subscription key: 先の手順でメモしたサブスクリプションキー
  • Parameters: id=1を指定
  • oauth2: authorization_codeを選択しログインする

準備ができたら「Send」をクリックします。200 OKが表示されたら成功です。

まとめ

想像以上に長い手順だったと思います。お疲れ様でした。

APIにアクセス制限ポリシーをカスタマイズすることでJWTの中に埋め込まれた情報をFunctionsに渡せそうに見えるのですが、そのあたりはまた次回検証したいと思います。

yuuu

yuuu

2018年の年明けに組込み畑からやってきた、2児の父 兼 Webエンジニアです。 mockmockの開発・運用を担当しており、組込みエンジニア時代の経験を活かしてデバイスをプログラミングしたり、簡易的なIoTシステムを作ったりしています。主な開発言語はRuby、時々Go。