Application Gatewayの背後にあるAPI Management、Function appを直接呼び出させないようにしたい

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

例によって以下のような問い合わせがあった。

問い合わせ

現在API ManagementとバックエンドサービスとしてFunction appを使い、APIを公開しようとしている。API Managementの前にWAFを配置するため、Application Gatewayを構成しようとしているのだが、現在利用しているAPI ManagementのSKUがBasicゆえ、VNetへのアクセスができない。このとき、API Management、Function appが直接呼び出されないようにするにはどうしたらよいか。

どうもこういうことらしい。

API Management、Function appとも、Premium SKUであればVNetに取り込めるのでこのような疑問に至ることはないのだが、お財布の事情があって、Function appはConsumption SKU、API ManagementはBasic SKUを使っている、とのこと。

解決案

以下は解決案の一つであり、これが唯一の解決案ではない。

  1. Application GatewayはPublic access用に構成しているので、Outbound IPはすでに割り当てているPublic IPが使われる。そのため、別途NAT Gatewayの配置をする必要はない。
  2. API Managementでは、Application GatewayのPublic IPからのアクセスのみを許可する。Subscription Keyを組み合わせることも可能。
  3. Function appでは、API ManagementのPublic IPからのアクセスのみを許可する。APIホストキーを使い(Function appでは承認レベルをfunctionにする必要がある)、API ManagementのManaged Identityで認証を組み合わせることもできる。

1. Application Gateway

これはそのまんまで、パブリックアクセス用にApplication Gatewayを構成しているため、すでにPublic IPが割り当て済みである。Outbound通信もこのIPを使うので、特に追加作業は必要ない(もちろん、明示的にOutbound用Public IPをNAT Gatewayに割り当て、Application GatewayのSubnetにNAT Gatewayを割り付けることもできる。この場合、Outbound通信はNAT Gatewayを通過する)。

Public Access用のPublic IPをそのまま使う
NAT Gatewayを配置する

2. API Management

Application Gatewayからのアクセスに限定するため、ip-filterポリシーを使う。このポリシーで、許可するIPアドレスとして、Application GatewayのPublic IP(NAT Gatewayを構成した場合には、NAT Gatewayに割り当てたPublic IP)を指定しておく。この設定はすべてのアクセスに対して有効にしたいので、グローバル スコープで構成しておく必要がある。グローバルスコープについては以下のドキュメントを参照。

グローバルスコープ / Global scope
https://docs.microsoft.com/azure/api-management/set-edit-policies#global-scope

ポリシーは以下のような感じ。

<policies>
    <inbound>
        <ip-filter action="allow">
            <address>xxx.xxx.xxx.xxx</address>
        </ip-filter>
    </inbound>
    <backend>
        <forward-request />
    </backend>
    <outbound />
    <on-error />
</policies>

Subscription Keyの利用強制と組み合わせれば、より強固ではある。Application Gatewayからの呼び出しでHTTP Headerに追加するように構成すればよい。

3. Function app

Function appでは、直接呼び出しを受けないよう、以下の構成を実施する。

  • IPアドレス制限
    API ManagementはPublic IPを持っているので、このIPからのアクセスのみを許可しておく
  • 認証を構成
    Function appで認証を構成し、同一Azure ADテナントに属するAzureリソースからのアクセスのみを許可する
  • ホストキーの強制
    承認レベルをfunctionにしておく

IPアドレス制限と認証だけでも問題ないが、すべて構成しておけばより強固ではある。以下ではIPアドレス制限と認証の構成について説明する。前者はFunction app、後者はFunction app、API Management両方での設定が必要。

a) IPアドレス制限

設定 > ネットワーク > 受信トラフィック > アクセス制限をクリックする。

表示されたタブのうち、scmという文字が入っていないタブを開き(通常、デフォルトで開いている)、【規則の追加】をクリックする。

開いた【アクセス制限の追加】画面で、以下の項目を入力する。

  • ルールの名前
  • アクション(今回は許可)
  • 優先度(デフォルトでもかまわない)
  • 説明(任意)
  • ソースの種類(今回はIPv4)。
    サービスタグはAPI Managementへのデプロイのための管理トラフィックに使われるSource IPを示しているので使えない。詳細は以下のURLを参照。

    利用可能なサービス タグ / Available service tags
    https://docs.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags
  • IPアドレスブロック(API ManagementのPublic IPを指定)

入力が完了したら【規則の追加】をクリックする。

b) 認証

Function app側では、認証を構成する。まず、設定 > 認証で【IDプロバイダーを追加】をクリックする。

続いて、IDプロバイダーはMicrosoftを選択する。これはAzure ADによるサインインを要求するもの。今回はManaged Identityを使うので、これを選択。

アプリの登録では、すでにFunction AppをAzure ADに登録済みであればその情報を選択。ここから新規登録することもできる。アクセス制限では「認証が必要」を選択し、トークンストアはONにしておく。ここまで終われば、【次へ:アクセス許可>】をクリックする。

【アクセス許可】はデフォルトでOK。最後に【追加】をクリックして完了。

追加が完了すると、右図のような画面が現れる。このアプリIDはAzure ADに登録されたFunction AppのClient IDである。このClient IDを使ってAPI Managementで認証を構成する。

API Management側では、システム割り当てのマネージドIDを作成しておく。これがないと認証できない。

その上で、Inboundパイプライン内でauthentication-managed-identityポリシーを追加し、そのポリシーで、対象リソースとしてFunction appのアプリID(Client ID)を指定する。スコープはAPIスコープを選択(オペレーションスコープだと個別設定になってしまう)。

<policies>
    <inbound>
        <base />
        <authentication-managed-identity resource="e56fc42a-f09a-4532-985b-7148da4089cd" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

これでおしまい。

テスト

Function appを直接呼び出すと、Function appが許可しているIPアドレスと異なるので当然怒られる(403)。

Application GatewayのIPアドレスのみを許可する設定を外している段階で、API Management経由でFunction appを呼び出すと、期待通りの動作をする(200)。なお、Subscription KeyはQuery Parameter (subscription-key) もしくはHTTP Header (Ocp-Apim-Subscription-Key) で指定する必要がある。もちろん、Subscription Keyなしでの呼び出しを許可していればその必要はない。

で、API ManagementでIPアドレス制限をかけて、Application Gatewayを経由しないで呼び出すと、当然ながら怒られる(403)。

最後に、Application Gatewayを経由して呼び出すと、問題なく呼び出されることがわかる(200。今回はテスト用途なのでHTTPを使った)。

Front Doorを使う場合

Front DoorではバックエンドプールにAPI Managementを追加することもできるようになっている。ただ、バックエンド向けIPがApplication Gatewayの場合と異なっていて、サービスタグ(AzureFrontDoor.Backend)としてまとめられている。これを使えばAPI ManagementのIPフィルターポリシーでフィルタリングできるが、以下の制限があるため、作業コストが高い。

  • API Managementではサービスタグを使ったIPアドレス制限ができないので、サービスタグに含まれているIPアドレスを逐一登録する必要がある
  • サービスタグのIPアドレスは予期なく変更されるため、追随するための作業コストが高い(もちろん、サービスタグのJSONファイルを読み取り、差分を検出して登録するよう、自動化する、という方法で担保することは可能だが、そこまでやるかを判断する必要がある)

そのため、作業コストを考えると、X-Azure-FDIDを使って制限をかけたほうが簡単であるが、これは厳密なアクセス制限にはならない点で注意が必要。

まとめ

上記の情報を提供したところ、Application Gateway > API Management > Function appのそれぞれで設定を追加してアクセス制限を施したようである。

簡易な方法であれば、Front DoorでもX-Azure-FDIDを使ってアクセス制限が可能だが、厳密にアクセス制限するのであれば、現時点ではApplication Gatewayを使うか、サービスタグAzureFrontDoor.BackendのIPアドレスを登録する必要がある(Front Door Standard/Premiumで利用可能なPrivate Link ServiceはまだAPI Managementに対応していない)。

ってここまで書いたところ、以下のエントリとほぼ同じ内容であった。

Integrate Azure Front Door with Azure API Management
https://techcommunity.microsoft.com/t5/azure-paas-blog/integrate-azure-front-door-with-azure-api-management/ba-p/2654925

コメントを残す

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

WordPress.com ロゴ

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

Google フォト

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

Twitter 画像

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

Facebook の写真

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

%s と連携中