ごった煮

色々な事を書いてます

API Management を Azure AD で保護する

はじめに

この記事は、Azure Advent Calendar 2021 の 15日目の記事になります。

qiita.com

本題

Azure のサービスで API を公開したい場合、API Management (以降 APIM) を使用すると、API の管理、保護などがサービスとして提供される為、 開発者は、API の開発に集中することが出来ます。

そんな中、昨今のセキュリティ意識の高まりから、よりセキュアな API の提供が求められていますが、高度なセキュリティを実装するとなると、かなりの労力や、実装ミスによるトラブル等 厄介な問題が付きまといます。

ということで今回は、Azure AD が提供する機能を使用して、APIM へのアクセスを保護する方法を説明します。

やってみる

前提条件

今回は、次の前提条件の下で作業するので、事前に準備をお願いします。

  • AAD にユーザを作る
  • APIM を作る
  • APIM で呼び出せるエンドポイントを1つ設定する

使用するツール

  • Postman (API 呼出しのチェック用)

Azure AD の設定

まずはじめに、Azure AD に新しくアプリケーションを登録します。

AAD > App registrations > New registration です。

f:id:papemk2:20211214204908p:plain

今回、アプリケーションの種別は、Public client / native (mobile & desktop) を選択します

Redirect URL は、https://oauth.pstmn.io/v1/callback を入力します。(Postman が提供する OAuth 2.0 用の Redirect URI です)

f:id:papemk2:20211214205729p:plain

アプリケーションが登録出来たら次は、Client Secret を生成します。

AAD のアプリケーション管理画面から、Certificates & secrets > New client secret を選択します。

f:id:papemk2:20211214210203p:plain

Secret が生成されたら、コピーします。(後で確認できなくなるので必ずコピーしてください)

f:id:papemk2:20211214210441p:plain

次に、アプリケーションにスコープを割り当てます

アプリケーション管理画面 > Expose an API > Add a scope を選択します。

f:id:papemk2:20211215123830p:plain

スコープを作成すると、用途などを聞かれるので、入力します。

Scope name の下に出ている URI は、コピーしておいてください。

f:id:papemk2:20211215123958p:plain

スコープが出来たら、スコープ名のテキストもコピーしておいてください。

f:id:papemk2:20211215124259p:plain

ここまで出来たら、残りの必要な情報をポータルから取得します。

まず Client Id です。 アプリケーション管理画面 > Overview > Application (Client) ID をコピーします。

f:id:papemk2:20211215105114p:plain

次に、テナント Id です

アプリケーション管理画面 > Overview > Directory (tenant) ID をコピーします。

f:id:papemk2:20211215131622p:plain

Azure AD の認証エンドポイント アプリケーション管理画面 > Overview > Endpoints > OAuth 2.0 authorization endpoint (v2)

Azure AD のトークンエンドポイント アプリケーション管理画面 > Overview > Endpoints > OAuth 2.0 token endpoint (v2)

OpenID Connect の well-known エンドポイント アプリケーション管理画面 > Overview > Endpoints > OpenID Connect metadata document

f:id:papemk2:20211215122032p:plain

Postman でアクセストークンを取得する

アクセストークンを取得する為の情報が揃ったので、アクセストークンを取得します。

Postman の Authorization タブ にて、下記の設定を行います。

項目 設定値
Type OAuth 2.0
Grant Type Authorization_Code
Authorize using browser チェックする
Auth URL 先ほどの認証エンドポイント
Access Token URL 先ほどのトークンエンドポイント
Client ID クライアント Id
Client Secret 生成した Secret
Scope openid offline_access 先ほど作ったスコープ

設定がセット出来たら、Get New Access Token ボタンを押します。

Azure AD の認証が入るので、作業をしていたディレクトリのアクセス情報でログインします。

ログインに成功すると、次の様な画面になります。

また、コールバック URL が https://oauth.pstmn.io/v1/callback?code={authorization_code}&session_state={セッションステート} となっており、code の値をコピーします。

この authorization_code を次のフローでアクセストークンに引き換えます。

※ authorization_code は、10分で切れるので、切れた場合は再取得します

f:id:papemk2:20211215105654p:plain

設定しているスコープについて

今回は、openid と offline_access を許可しています。

これらはそれぞれ、

openid : OpenID Connect を使用してサインインする場合に必須なスコープです。このアクセス許可があると、アプリは、ユーザの一意識別子を取得できます。

offline_access : アプリがユーザの代わりに長期間アクセス権を得ることが出来るようになるスコープです。このアクセス許可を指定することで、アクセストークン取得時に、refresh_token を合わせて取得できるようになります。

また、自身が保護したいアプリの要求するスコープを適宜追加することも可能です。(APIM の API を read のみ出来るカスタムスコープなど)

authorization_code をアクセストークンに引き換える

先ほど取得した authorization_code から、 先ほど取得したトークンエンドポイントに対して、次のパラメータで POST リクエストを送ります

項目 設定値
Content-Type application/x-www-form-urlencoded
code authorization_code
client_id クライアント Id
grant_type authorization_code
scope openid offline_access 先ほど作ったスコープ
redirect_uri https://oauth.pstmn.io/v1/callback(最初に登録した Redirect URL)

成功すると、次の様な json が返ってきます。

{
    "token_type": "Bearer",
    "scope": "指定したスコープ",
    "expires_in": アクセストークンの有効期限(秒),
    "ext_expires_in": Azure AD のセキュリティトークンサービスが停止していた場合のトークンの最大延長期限,
    "access_token": "アクセストークン",
    "refresh_token": "リフレッシュトークン",
    "id_token": "id トークン"
}

これにより、アクセストークン、リフレッシュトークンが取得できました。

これ以降、API 呼出しは、access_token の値を Authorize ヘッダに Bearer トークンとしてセットして使用します。

また、アクセストークンの有効期限は非常に短い為、リフレッシュトークンを使用して、常にアクセストークンを新しくしていく必要があります。

リフレッシュトークンでトークンを更新する

トークンエンドポイントに対して、次のパラメータで POST リクエストを送ります。

項目 設定値
Content-Type application/x-www-form-urlencoded
refresh_token リフレッシュトーク
client_id クライアント Id
grant_type refresh_token
scope openid offline_access 先ほど作ったスコープ

これにより、新しいアクセストークン、リフレッシュトークンが返されます

リフレッシュトークンの有効期限も、デフォルトで90日なので、トークン更新のタイミングで一緒に交換する等を検討する必要があります。

{
    "token_type": "Bearer",
    "scope": "指定したスコープ",
    "expires_in": アクセストークンの有効期限(秒),
    "ext_expires_in": Azure AD のセキュリティトークンサービスが停止していた場合のトークンの最大延長期限,
    "access_token": "アクセストークン",
    "refresh_token": "リフレッシュトークン",
    "id_token": "id トークン"
}

APIM を構成する

アクセストークンを取得できましたが、APIM は、デフォルトで Authorization ヘッダを検証しない為、トークンを使わなかったり、適当なトークンを投げられた場合も素通りします。

そこで、Azure AD で取得したアクセストークンを APIM で解析する設定を追加します。

アクセストークンは、jwt なので、APIM で事前に Authorization ヘッダの jwt を検証する仕組みを追加します。

早速 APIM の設定を行いましょう

APIM の管理画面 > APIs > 設定したい API > All APIs(それぞれの API でも可) > Inbound processing に進みます。

f:id:papemk2:20211215121643p:plain

Add Policy を選択すると、その中に Validate JWT の項目があるので選択します

f:id:papemk2:20211215121729p:plain

次の画像の様にフォームを埋めて保存します。

Basic だと、Issuer を埋められないので、Full を選択します。

f:id:papemk2:20211215131826p:plain

これで APIM の基本構成が出来ました。

Postman にて、Authorize ヘッダに Bearer トークンとしてアクセストークンをセットすれば、正しくアクセスできるはずです。

まとめ

これにて、Azure AD を使って APIM を保護できるようになりました。

手順はたくさんありますが、一度設定してしまえば、後は API を呼び出すだけなので、セキュリティを強化するという意味で是非やってみましょう。

今回は、かなり説明を割愛した部分があるので、次回以降それぞれの項目を深堀していく記事を書いていく予定です。