🔐

Azure API Management における認証と認可

に公開

Azure API Management における認証と認可

API の認証・認可を設計するとき、まず どのような認証・認可パターンが存在するか を理解し、その上で APIM(Azure API Management)ではどうアプローチするか を考えるのが自然な流れです。本記事はこの順序で解説します。

  • 認証・認可の基本パターン(APIM に依存しない一般論)
  • APIM での認証の実現方法(インバウンド/アウトバウンド/パススルー)
  • APIM での認可 ― できること・できないこと・やるべきでないこと
  • APIM 固有の「サブスクリプションキー/製品」や利用制御(補足)
  • ネットワークレベルの分離(classic / v2 / 各プラン差分を踏まえて)

関連記事


1. 認証認可の基本パターン

APIM の話に入る前に、API における認証・認可の一般的なパターンを整理します。

1.1 認証(Authentication)― 誰であるかを確認する

パターン 仕組み 代表的なプロトコル/実装
トークンベース認証 クライアントが IdP から取得したトークン(JWT 等)を提示し、サーバーが署名・有効期限・発行者などを検証する OAuth 2.0 / OpenID Connect
API キー認証 事前に発行した秘密キーをリクエストに含めて送信する API キー(ヘッダー / クエリ)
証明書認証(相互 TLS) クライアントが自身の証明書を提示し、サーバーが CA チェーンを検証する mTLS
Basic 認証 ユーザー名とパスワードを Base64 エンコードして送信する(現在では推奨されにくい) HTTP Basic

1.2 認可(Authorization)― 何を許可するかを決定する

認可には大きく分けて以下のモデルがあります。

モデル 判断基準
RBAC(ロールベース) ユーザーに割り当てられたロール 「admin ロールなら全操作可」「reader なら GET のみ」
委任スコープ ユーザーがアプリに委任した権限(OAuth スコープ) 「Files.Read を許可したアプリのみ読み取り可」
ABAC(属性ベース) ユーザー属性・リソース属性・環境条件の組み合わせ 「部署 X が営業時間内に自部署データへ」
リソースオーナーチェック リクエスト対象リソースの所有者 「自分が作成した注文のみ閲覧可能」
ビジネスルールベース アプリ固有のドメインロジック 「月間利用量が上限未満の場合のみ」

重要な点: 上の表で下に行くほど、認可判断に必要な情報がトークンのクレームだけでは足りなくなります。
RBAC や委任スコープはトークン内のクレーム(roles, scp など)で完結しやすい一方、ABAC やリソースオーナーチェック、ビジネスルールベースの認可は DB や外部サービスへの問い合わせが不可欠 になりがちです。
この違いが、後述する「APIM で認可をどこまでやるべきか」の判断に直結します。


2. APIM での認証の実現

APIM は認証を 3 つの境界で制御できます。

  • クライアント → APIM(インバウンド認証)
  • APIM → バックエンド(アウトバウンド認証)
  • パススルー(APIM が認証に介在しない)

2.1 クライアント → APIM(インバウンド認証)

クライアントが APIM に対して「誰であるか」を証明します。APIM がインバウンド認証を担うことで、バックエンドはクライアントごとの認証処理を持たなくて済みます。

方式 概要 主なユースケース
API キー(サブスクリプションキー) ヘッダー / クエリでキーを渡す シンプルな API 公開・パートナー向け
JWT 検証(validate-jwt) Bearer トークンの署名・期限・発行者・aud 等を検証 Entra 以外の IdP を含む汎用 JWT 検証 [learn.microsoft.com]
Entra トークン検証(validate-azure-ad-token) Entra が発行した JWT を検証(Entra 専用の検証) [learn.microsoft.com] 社内向け API・B2B 統合
クライアント証明書(相互 TLS) クライアント証明書を検証 高セキュリティが必要な B2B
IP フィルタリング 特定 IP アドレス/レンジのみ許可/拒否 ネットワーク境界での制限

これらは ポリシーとして <inbound> フェーズに挿入します。


2.1.1 validate-jwt(汎用 JWT)の例(Entra 以外 IdP も含む)

validate-jwt は 任意の IdP が発行した JWT を検証できます(OIDC discovery を使うか、署名鍵を指定)。Entra の JWT も検証できますが、Entra 専用の検証を明示したい場合は validate-azure-ad-token を選ぶのが分かりやすいです。 [learn.microsoft.com], [learn.microsoft.com]

<policies>
  <inbound>
    <base />

    <!-- 汎用 JWT 検証:任意の IdP が発行したトークンを検証する -->
    <validate-jwt header-name="Authorization"
                  failed-validation-httpcode="401"
                  failed-validation-error-message="Unauthorized. Invalid or missing token."
                  require-expiration-time="true"
                  require-scheme="Bearer"
                  require-signed-tokens="true"
                  output-token-variable-name="jwt">

      <!-- OIDC discovery で署名鍵を自動取得(例:Okta/Auth0 等の well-known) -->
      <openid-config url="https://idp.example.com/.well-known/openid-configuration"
                    validate-connectivity="true" />

      <!-- aud / iss を明示して意図しないトークン流用を防ぐ -->
      <audiences>
        <audience>api://my-api-app-id</audience>
      </audiences>

      <issuers>
        <issuer>https://idp.example.com/</issuer>
      </issuers>

      <!-- スコープ "read" を持つトークンのみ許可 -->
      <required-claims>
        <claim name="scope" match="any" separator=" ">
          <value>read</value>
        </claim>
      </required-claims>
    </validate-jwt>

  </inbound>
  <backend>
    <forward-request />
  </backend>
</policies>

実務上の注意(事故が多いポイント)

  • require-scheme="Bearer" を指定すると、Authorization ヘッダーに Bearer が付いていることを強制できます。 [learn.microsoft.com]
  • require-expiration-timeexp クレームを必須にするか を制御します(既定は true)。トークン期限の検証を “必ず行う” 方針なら true を明示しておくと安全です。 [learn.microsoft.com]
  • APIM が VNet に 注入(injection)/統合(integration) され、openid-config の URL が プライベート DNS/名前解決の都合で到達性チェックに失敗する場合、validate-connectivity=”false” で “到達性チェックのみ” を無効化できます(トークン検証そのものを無効化するものではありません)。 [learn.microsoft.com]

2.1.2 validate-azure-ad-token(Entra 専用)の例

validate-azure-ad-token は Entra が発行した JWT を検証するためのポリシーです。ヘッダー/クエリ/式からトークンを抽出でき、audiences / required-claims 等を指定できます。 [learn.microsoft.com]

<policies>
  <inbound>
    <base />

    <!-- Entra ID 専用のトークン検証(tenant-id でテナントを限定) -->
    <validate-azure-ad-token tenant-id="{{aad-tenant-id}}"
                             header-name="Authorization"
                             failed-validation-httpcode="401"
                             failed-validation-error-message="Unauthorized. Invalid or missing token."
                             output-token-variable-name="jwt">
      <!-- 対象 API の audience を指定 -->
      <audiences>
        <audience>api://my-api-app-id</audience>
      </audiences>

      <!-- api.read ロールを持つトークンのみ通過 -->
      <required-claims>
        <claim name="roles" match="any">
          <value>api.read</value>
        </claim>
      </required-claims>
    </validate-azure-ad-token>

  </inbound>
  <backend>
    <forward-request />
  </backend>
</policies>

Entra 以外の IdP の JWT を検証する場合は validate-jwt を使います。 [learn.microsoft.com], [learn.microsoft.com]


2.2 APIM → バックエンド(アウトバウンド認証)

クライアント認証が通過した後、APIM がバックエンドに対して認証します。バックエンドに直接アクセス制御をかけつつ、クライアントには認証情報を渡さない ための仕組みです。

方式 概要 主なユースケース
マネージド ID APIM の managed identity で Entra からアクセストークンを取得し、バックエンドへ送る(Authorization: Bearer を設定、期限までキャッシュ) Azure リソース(Functions / Key Vault / OpenAI 等)への推奨方式
Credential Manager OAuth 2.0 接続を APIM が管理し、get-authorization-context でアクセストークン/更新を取得して付与 [learn.microsoft.com] Graph・Salesforce・GitHub 等の SaaS 連携(MI が使えない場合も)
クライアント証明書 Key Vault 等に格納した証明書でバックエンドへ mTLS B2B バックエンド
Basic 認証 Named Values / Key Vault に格納した資格情報を付与 レガシー(推奨度低)

2.2.1 マネージド ID によるアウトバウンド認証の例

authentication-managed-identity は、指定 resource 向けトークンを取得し、Authorization ヘッダーへ Bearer として設定し、トークンを期限までキャッシュします。

<policies>
  <inbound>
    <base />

    <!-- マネージド ID でバックエンド用トークンを取得し Authorization ヘッダーに設定 -->
    <authentication-managed-identity resource="https://cognitiveservices.azure.com"
                                     output-token-variable-name="msi-access-token" />
  </inbound>

  <backend>
    <forward-request />
  </backend>
</policies>

必要に応じて、output-token-variable-name を使ってヘッダーを手動でセットするパターンも公式例として示されています。


2.2.2 Credential Manager(get-authorization-context)の位置づけと例

Credential Manager は OAuth 2.0 接続(connection)を APIM 側で管理し、ランタイムでは get-authorization-contextアクセストークンの有効性確認 → 必要なら refresh → トークン返却/付与 を行います。 [learn.microsoft.com]

<policies>
  <inbound>
    <base />

    <!-- Credential Manager から OAuth トークンを取得(自動 refresh 付き) -->
    <get-authorization-context provider-id="my-provider"
                               authorization-id="my-connection"
                               context-variable-name="auth-context"
                               identity-type="managed"
                               ignore-error="false" />

    <!-- 取得したトークンを Authorization ヘッダーにセット -->
    <set-header name="Authorization" exists-action="override">
      <value>@("Bearer " + ((Authorization)context.Variables.GetValueOrDefault("auth-context"))?.AccessToken)</value>
    </set-header>
  </inbound>

  <backend>
    <forward-request />
  </backend>
</policies>

実務上の注意(導入可否に直結)

  • get-authorization-context には identity-type="managed | jwt" があり、接続の access policy に対して APIM の managed identity で許可判定するか呼び出し元 JWT(identity 属性)で許可判定するかを選べます。
  • Credential Manager は workspaces 非対応self-hosted gateway 非対応 など制約があります(外部公開 API で self-hosted gateway を前提にする場合は要注意)。 [learn.microsoft.com], [learn.microsoft.com]
  • トークンキャッシュの挙動や前提条件(managed identity 必須、アウトバウンド 443 必須など)は公式にまとまっています。 [learn.microsoft.com]

2.3 パススルー認証(APIM が認証に介在しないパターン)

APIM を経由してリクエストは通るが、認証自体はクライアントとバックエンドが直接やり取りする構成です。APIM はルーティング・ログ・レート制限などの横断的関心事だけを担い、認証トークンや資格情報には手を加えずそのままバックエンドに転送します。

クライアント
   │ Bearer トークン(バックエンドが検証)
   ▼
┌──────────────────────────┐
│ APIM(ルーティング/制限/ログ) │
│ ※認証トークンは透過           │
└──────────────────────────┘
   │
   ▼
バックエンド(トークンを検証して認証・認可)
<policies>
  <inbound>
    <base />
    <!-- 認証は行わず、レート制限のみ適用(トークンはそのままバックエンドへ転送) -->
    <rate-limit-by-key calls="100" renewal-period="60"
                       counter-key="@(context.Request.IpAddress)" />
  </inbound>
  <backend>
    <forward-request />
  </backend>
</policies>

パススルー認証が選択される場面(より正確な言い方)

  • トークンが JWT ではない、または APIM の validate-jwt が対応しない署名/暗号方式、鍵配布方式、検証要件(例:特殊な introspection 依存)である
  • IdP が OIDC discovery を提供しない/ネットワーク上の制約で検証に必要なメタデータ取得が難しい(ただし validate-connectivity の調整などで解消できる場合もある) [learn.microsoft.com]
  • バックエンド側に既存の認証・認可ロジックが深く組み込まれており、移行コストが高い
  • 複数バックエンドがそれぞれ異なる方式を持ち、APIM で統一するより各バックエンドに任せた方が合理的

パススルー認証のリスクと対策

リスク 対策
APIM が不正リクエストを早期に弾けない(バックエンドに負荷が到達) レート制限 / IP 制限 / WAF 等で “認証前” の流量を制御する
認証実装が分散し、一貫性が保証しにくい 認証ライブラリやミドルウェアを共通化し、長期的には APIM 側での検証に統一検討
APIM のログにユーザー情報が残りにくい 可能な範囲でヘッダー・クレーム抽出を行い、監査観点を補う(ただし未検証クレームの扱いには注意)

推奨: パススルー認証は移行期や特殊要件がある場合の選択肢です。可能であれば APIM でインバウンド認証(トークン検証)を担う構成に統一する方が、セキュリティの一元管理・早期排除・監査の面で有利です。 [learn.microsoft.com], [learn.microsoft.com]


3. APIM での認可 ― できること・できないこと・やるべきでないこと

3.1 認可の本質:判断に必要な情報はどこにあるか

認可を設計するとき、最も重要な問いは 「認可判断に必要な情報はどこにあるか」 です。

  • トークンのクレームだけで完結するなら、APIM のポリシーで完結しやすい(APIM 向き)
  • DB / 外部サービス参照が必要なら、APIM ではなくアプリケーション/専用認可サービスが主戦場(APIM 不向き)

<!---->

トークンのクレームだけで判断できる        DB/外部参照が必要
◄──────────────────────────────►
 RBAC(roles) / スコープ(scp)            ABAC / オーナー / ビジネスルール
   ↑ APIMで扱いやすい                     ↑ アプリ側で扱うのが自然

APIM の validate-jwt / validate-azure-ad-tokenrequired-claims によって、クレームベースの認可(=ゲートでの簡易認可)を表現できます。 [learn.microsoft.com], [learn.microsoft.com]


3.2 現実:カスタマイズしていない Entra ID を使う場合

多くの組織では、Entra ID を「そのまま」(特別なカスタマイズなしで)IdP として使います。この場合、トークンに含まれるクレームは限定的です。

標準的に含まれやすいもの

含まれない/不足しがちなもの

  • 業務上の属性(部署・役職・所属情報の全て)
  • リソースの所有者情報
  • ビジネス状態(承認済み/利用量/ステータス等)
  • 他システムにあるユーザー属性

したがって、“Entra ID + APIM だけで完結できる認可” は基本的に roles/scp のようなクレームベースに寄ります[learn.microsoft.com], [learn.microsoft.com]


3.3 APIM で認可を行うべきケース

以下の条件を すべて 満たす場合、APIM での認可は合理的です。

  • 認可判断がトークン内のクレーム(roles, scp 等)だけで完結する [learn.microsoft.com], [learn.microsoft.com]
  • 認可ルールが「このクレームがあれば通す/なければ拒否」という単純な構造
  • 認可ルールの変更頻度が低く、ポリシー変更(デプロイ/リビジョン運用)が許容される

RBAC(roles クレーム)での認可例

<policies>
  <inbound>
    <base />
    <!-- RBAC 認可:api.write ロールを持たないリクエストは 403 で拒否 -->
    <validate-azure-ad-token tenant-id="{{tenant-id}}"
                             failed-validation-httpcode="403"
                             failed-validation-error-message="Forbidden. Required role is missing.">
      <audiences>
        <audience>api://my-api-app-id</audience>
      </audiences>
      <required-claims>
        <claim name="roles" match="any">
          <value>api.write</value>
        </claim>
      </required-claims>
    </validate-azure-ad-token>
  </inbound>
  <backend>
    <forward-request />
  </backend>
</policies>

validate-azure-ad-token の要素(audiences / required-claims 等)は公式仕様に沿って記述します。 [learn.microsoft.com]

委任スコープ(scp)での認可例

<policies>
  <inbound>
    <base />
    <!-- 委任スコープ認可:Files.Read スコープを持たないリクエストは 403 -->
    <validate-azure-ad-token tenant-id="{{tenant-id}}"
                             failed-validation-httpcode="403">
      <audiences>
        <audience>api://my-api-app-id</audience>
      </audiences>
      <required-claims>
        <claim name="scp" match="any" separator=" ">
          <value>Files.Read</value>
        </claim>
      </required-claims>
    </validate-azure-ad-token>
  </inbound>
  <backend>
    <forward-request />
  </backend>
</policies>

3.4 APIM で認可をやるべきでないケース ― アプリ側に任せるべき認可

以下のいずれかに該当する場合、APIM は認証(トークン検証)にとどめ、認可はアプリケーション側で行うべきです。

  • リソースの所有者チェックが必要(「自分のデータだけ閲覧可能」)
  • ビジネスルールに基づく判断が必要(「利用上限に達していないか」「承認済みか」)
  • ユーザー属性を DB から取得する必要がある
  • 認可ルールが頻繁に変わり、APIM ポリシーの再デプロイが運用上現実的でない

なぜアプリ側で行うべきか

  • 情報の所在:必要情報(所有権、状態)はアプリ DB にあり、APIM で安全に扱うのは難しい
  • 関心の分離:APIM はインフラ層。ビジネスロジックが APIM とアプリに分散すると保守性が落ちる
  • テスト容易性:アプリ内の認可はユニットテストで検証しやすいが、ポリシーに埋め込むほど難しくなる

推奨アーキテクチャ:APIM は認証、アプリは認可

<policies>
  <inbound>
    <base />

    <!-- APIM はトークン検証(認証)のみ担当し、認可はバックエンドに委ねる -->
    <validate-jwt header-name="Authorization"
                  failed-validation-httpcode="401"
                  failed-validation-error-message="Unauthorized. Invalid or expired token."
                  require-scheme="Bearer"
                  output-token-variable-name="jwt">
      <openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
      <audiences>
        <audience>api://my-api-app-id</audience>
      </audiences>
      <issuers>
        <issuer>https://login.microsoftonline.com/{tenant-id}/v2.0</issuer>
      </issuers>
      <!-- required-claims は "最小限" に。複雑な認可はアプリへ -->
    </validate-jwt>

    <!-- JWT の oid クレームをカスタムヘッダーでバックエンドへ転送 -->
    <set-header name="X-User-ObjectId" exists-action="override">
      <value>@(((Jwt)context.Variables["jwt"])?.Claims.GetValueOrDefault("oid",""))</value>
    </set-header>
  </inbound>

  <backend>
    <forward-request />
  </backend>
</policies>

validate-jwt の属性や openid-config の扱いは公式仕様に沿って設計します。 [learn.microsoft.com]


3.5 外部認可サービスとの連携(高度なケース)

例外的に、APIM から外部の専用認可サービス(OPA、Cedar、カスタム認可 API 等)に問い合わせる構成も可能です。ただしこれは 認可サービスが認可に必要な情報をすべて持っている(または取得できる) 場合に限られます。

クライアント → APIM → [send-requestで認可サービスへ]
   │
   ├─ 許可 → バックエンドへ
   └─ 拒否 → 403
<policies>
  <inbound>
    <base />

    <!-- まず認証(例:validate-jwt / validate-azure-ad-token)を実施 -->

    <!-- 外部認可サービスへ判定を委任 -->
    <send-request mode="new"
                  response-variable-name="authzResponse"
                  timeout="10"
                  ignore-error="true">
      <set-url>https://authz-service.internal/authorize</set-url>
      <set-method>POST</set-method>
      <set-header name="Content-Type" exists-action="override">
        <value>application/json</value>
      </set-header>
      <set-body>@{
        return new JObject(
          new JProperty("subject", context.Request.Headers.GetValueOrDefault("X-User-Id","")),
          new JProperty("action", context.Request.Method),
          new JProperty("resource", context.Request.Url.Path)
        ).ToString();
      }</set-body>
    </send-request>

    <!-- 認可サービスの応答が 200 以外なら 403 を返す -->
    <choose>
      <when condition="@(((IResponse)context.Variables["authzResponse"]).StatusCode != 200)">
        <return-response>
          <set-status code="403" reason="Forbidden" />
          <set-body>{"error": "Authorization denied by policy engine"}</set-body>
        </return-response>
      </when>
    </choose>
  </inbound>

  <backend>
    <forward-request />
  </backend>
</policies>

send-request 自体は一般的なポリシーですが、本節は概念説明(設計パターン)として提示しています。

外部認可サービスを検討すべきケース

  • 同じ認可ルールを APIM 以外のサービス(バックエンド・他ゲートウェイ)でも適用したい
  • 認可の監査ログを認可サービス側に一元化したい
  • 認可サービスがユーザー属性・リソース属性を管理している

3.6 認可パターン選定フロー(簡易)

  1. 認可判断に必要な情報は トークンのクレームだけで足りるか?
    • YES → 2 へ
    • NO → 3 へ
  2. 認可ルールは「クレームの有無」だけで表現できるか?
  3. 認可判断に必要な情報は外部認可サービスが持っているか?
    • YES → APIM から外部認可へ委任
    • NO → アプリケーション側で認可(APIM は認証のみ)

4. (補足)APIM 固有のアクセス制御:サブスクリプションキー/製品/利用制御

この記事は主に “認証(AuthN)/認可(AuthZ)” の話をしていますが、APIM には API 公開の運用に直結する固有概念があります。

4.1 サブスクリプションキーは「認証」ではなく「契約/アプリ識別」の軸になりやすい

  • APIM の rate-limit(by subscription)quota(by subscription)サブスクリプションキーに依存します。 [learn.microsoft.com]
  • そのため「JWT で認証しているから subscription key は不要」とすると、“利用制御・可観測性・契約単位の運用” の軸を失う可能性があります。
  • 現場では、JWT(誰か)subscription key(どの契約/どのアプリか) を併用する設計もよくあります(例:外部公開 API で契約単位のレート制限を維持しつつ、ユーザー認証は JWT)。

“by subscription” のポリシーが subscription key に依存する点は公式に明記されています。 [learn.microsoft.com]

4.2 代替:subscription key を使わずにレート制限したい場合

subscription key を必須にしない場合でも、rate-limit-by-key のように 任意キー(IP、クライアントID、JWT のクレーム等) でカウンタを切る設計が取れます(詳細はポリシー設計次第)。
※この話は「認証」ではなく「利用制御(保護)」の話ですが、外部公開では重要になりやすい領域です。 [learn.microsoft.com]


5. ネットワークレベルの分離(classic / v2 / プラン差分の注意)

認証に加え、ネットワーク境界での分離も組み合わせることが多いです。ここでは “概念” を押さえつつ、v2 系(Basic v2 / Standard v2 / Premium v2)と classic 系(Developer / Premium など)で差が出るところは注記します。

5.1 典型的な選択肢(目的別)

  • 受信(inbound)を閉域にしたい:プライベート到達に寄せる(プラン/方式により構成が異なる)
  • 送信(outbound)を閉域にしたい:バックエンドを VNet 内に置き、APIM から VNet 経由で到達させる
  • 受信も送信も閉域にしたい:APIM 自体を VNet に深く組み込む

5.2 Premium v2 の VNet injection に関する重要制約

5.3 認証系機能とネットワークの相互作用(よくある落とし穴)

  • validate-jwt / openid-config を使う場合、APIM から IdP のメタデータ取得が必要になります(DNS/到達性の設計が必要)。到達性チェックが問題になる場合は validate-connectivity の調整が可能です。 [learn.microsoft.com]
  • Credential Manager は「APIM から外部へのアウトバウンド 443」等が前提になり、VNet 内の閉域化設計では “外へ出る経路” の確保が必要になります。 [learn.microsoft.com]

参考リンク

  • Azure API Management ポリシーリファレンス(一覧): Microsoft Learn
  • validate-jwt(汎用 JWT 検証): Microsoft Learn
  • validate-azure-ad-token(Entra トークン検証): Microsoft Learn
  • authentication-managed-identity(MI でバックエンド認証): Microsoft Learn
  • get-authorization-context(Credential Manager のランタイム利用): Microsoft Learn
  • Credential Manager 概要(制約・要件・キャッシュ等): Microsoft Learn
  • Premium v2 の VNet injection(制約含む): Microsoft Learn

付録:Entra ID と他 IdP 混在時の “現実的な運用指針”(短く)

  • API 単位で IdP を統一できるなら統一:APIM ポリシー/監査/運用がシンプルになる
  • 混在するなら “検証方法の標準化” を先に決める
  • クレーム設計(aud/iss/scope/roles)は “契約” として固定:後から変えるとクライアント全滅級の影響が出る
ヘッドウォータース

Discussion