このエントリは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を使っている、とのこと。
解決案
以下は解決案の一つであり、これが唯一の解決案ではない。
- Application GatewayはPublic access用に構成しているので、Outbound IPはすでに割り当てているPublic IPが使われる。そのため、別途NAT Gatewayの配置をする必要はない。
- API Managementでは、Application GatewayのPublic IPからのアクセスのみを許可する。Subscription Keyを組み合わせることも可能。
- 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を通過する)。


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