Azure API ManagementとCORS

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

CORSとは?

CORSの定義などは種々のコンテンツに記載があるので、そちらを参照のこと。以下はその一例。

オリジン間リソース共有 (CORS) / Cross-Origin Resource Sharing (CORS)
https://developer.mozilla.org/docs/Web/HTTP/CORS

CORSの設定をしたからといって、CSRF(Cross site request forgery)攻撃に対する防御としては有効ではない点は留意しておかねばならない(ちゃんとセキュリティ設計はしましょ、ということ)。

GatewayでのCORS許可の挙動

APIMのGatewayは外部サービスとのアクセス、つまりドメイン外のリソースにアクセスするので、CORSが可能になるよう、Pre-flightリクエストの後に実際のバックエンドサービスへのリクエストを投げている。

説明のため、以下のような構成を考える。

  • testclient.azure-api.net:APIMと同一ドメインに存在するテストクライアント
  • backend.azure-api.net:APIMと同一ドメインに存在するバックエンドサービス
  • testclient.foo.com:APIMのドメイン外に存在するテストクライアント(セルフホスト開発者ポータルに読み替えてもよい)
  • api.contoso.net:APIMのドメイン外に存在するバックエンドサービス

backend.azure-api.netをバックエンドサービスとして使うAPIであればCORSを意識する必要はないが、api.contoso.netをバックエンドサービスとして使うAPIの場合、ドメインを跨ぐのでCORSを許可してもらうよう、バックエンドサービスに対してリクエストする必要がある。

なお、この例ではGatewayにのみフォーカスするため、testclient.azure-api.netからの呼び出しを想定する。その後外部ドメインのクライアントからのアクセスのためのCORSポリシー設定について考える。

1. クライアントからGatewayに向けてリクエストを送信

ひとまず、testclient.azure-api.netからリクエストを投げる。ここは通常通り。

2-1 GatewayからバックエンドサービスへのPre-flightリクエスト

今回、api.contoso.netへリクエストを渡すので、Gatewayはapi.contoso.netへPre-flight requestを投げ込む。

2-2 Pre-flight レスポンス

api.contoso.netからのレスポンスでCORSを許可されると、Access-Control-*でその許可内容が渡される。以下の例で許可されたものは…。

  • HTTP verbs: POST、GET、OPTIONS
  • Header: X-Custom-Header、Content-Type
  • 有効期間: 86400秒(24時間)

2-3 実際のバックエンドサービスへのリクエストを投げる

許可された後に、ようやくバックエンドサービスへ本来のリクエストを投げることができる。

2-4 バックエンドサービスからのレスポンスをGatewayで受け取る

api.contoso.netから返ってきたレスポンスをGatewayが受け取る。

3. レスポンスをクライアントへ返す

Gatewayはapi.contoso.netから返ってきたレスポンスを必要に応じて加工したのちに、クライアントtestclient.azure-api.netへ返す。

Azure API Management(以下、APIM)でのCORS(Cross-Origin Resource Sharing)ポリシー

GatewayでのCORSの許可を得るフローが理解できれば、このポリシーで何を設定しようとしているかが分かる(はず、知らんけど)。

このポリシーで実現しようとしているのは、APIM(ここではGateway)に対してアクセスしてくるクライアント(PostmanやWebアプリケーションなど)が、Gatewayと同一ドメインにない場合、Gatewayを呼び出す際にPre-flightリクエストを投げ込む必要がある。そのPre-flightリクエストに対するGatewayでの振る舞いを設定しよう、というもの(下図の赤矢印で届くリクエストに対する振る舞い)。それゆえ、CORSポリシーはInbound-processingのパイプライン内に配置される。

ドキュメントは以下の通り。

CORS
https://docs.microsoft.com/azure/api-management/api-management-cross-domain-policies#CORS

<allowed-origins>要素には複数のオリジンを指定できる。このあたりはAzure FunctionsのCORS設定と同じ。以下のポリシーの例では、以下の2個のオリジンからのアクセスも許可している。

<cors allow-credentials="true">
    <allowed-origins>
        <!-- Localhost useful for development -->
        <origin>http://localhost:8080/</origin>
        <origin>http://example.com/</origin>
    </allowed-origins>
    <allowed-methods preflight-result-max-age="300">
        <method>GET</method>
        <method>POST</method>
        <method>PATCH</method>
        <method>DELETE</method>
    </allowed-methods>
    <allowed-headers>
        <!-- Examples below show Azure Mobile Services headers -->
        <header>x-zumo-installation-id</header>
        <header>x-zumo-application</header>
        <header>x-zumo-version</header>
        <header>x-zumo-auth</header>
        <header>content-type</header>
        <header>accept</header>
    </allowed-headers>
    <expose-headers>
        <!-- Examples below show Azure Mobile Services headers -->
        <header>x-zumo-installation-id</header>
        <header>x-zumo-application</header>
    </expose-headers>
</cors>

開発者ポータルの対話コンソールで設定したCORSポリシー

以前開発者ポータルのエントリで、対話コンソールからのAPIテスト呼び出しのためのCORSポリシー適用が可能と書いた。このCORSポリシーはグローバルレベルで設定されている。

Azure API Managementの開発者ポータル
https://logico-jp.io/2020/07/10/new-azure-api-management-developer-portal/

対話コンソールからのアクセスを許可、つまり開発者ポータルからのアクセスを許可したいので、このポリシーの設定では、オリジンとしてAPIM開発者ポータルのURLが入っている。

<cors allow-credentials="true">
    <allowed-origins>
        <origin>https://(APIMインスタンス名).developer.azure-api.net</origin>
    </allowed-origins>
    <allowed-methods preflight-result-max-age="300">
        <method>*</method>
    </allowed-methods>
    <allowed-headers>
        <header>*</header>
    </allowed-headers>
    <expose-headers>
        <header>*</header>
    </expose-headers>
</cors>

コメントを残す

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

WordPress.com ロゴ

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

Google フォト

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

Twitter 画像

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

Facebook の写真

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

%s と連携中