Azure 上でゼロトラストな API 基盤を作ろうとすると、Application Gateway・API Management(APIM)・Function App をどのように組み合わせて外部公開するかで悩みがちです。本記事では「クライアント → App Gateway → APIM(内部) → Function App(プライベート)」という構成を前提に、実際に外部公開する際の正しいエンドポイント、設定手順、さらに Postman でのテスト方法までを、現場目線で詳しく解説します。
前提シナリオとゴールの整理
まずは前提となる構成と、この記事で解決したいポイントを整理します。
想定している構成は次のとおりです。
- クライアント:インターネット上の外部クライアント(ブラウザ、モバイルアプリ、サーバーなど)
- Application Gateway:パブリック IP を持つ WAF 対応の L7 ロードバランサー
- API Management(APIM):内部モード(VNet 内)で稼働し、パブリックには一切公開しない
- Function App:VNet 統合+プライベートエンドポイントにより外部非公開のサーバーレス実装
この構成でよく出てくる疑問は次の 3 つです。
- 外部クライアントに案内すべき 正しい URL(エンドポイント) は何か?
- 実際に外部公開するまでの 具体的な構成手順 はどうなるか?
- Postman で動作確認する際、どのヘッダー・認証情報 を付ければよいか?
結論を先に言うと、外部クライアントに知らせるべき URL は Application Gateway に割り当てた独自ドメインの HTTPS URL だけ です。
例:
APIM や Function App の内部アドレス(プライベート IP・プライベート FQDN)は、原則クライアントに教える必要はありませんし、教えてはいけません。以降、その理由と構成方法を詳しく見ていきます。
全体アーキテクチャと通信フロー
最初に、コンポーネントごとの役割と通信フローを整理しておきます。
| コンポーネント | 役割 | 外部公開の有無 |
|---|---|---|
| クライアント | API を呼び出すアプリケーション。HTTP(S) リクエストの発信元。 | インターネット上の任意クライアント |
| Application Gateway | インターネット入口。WAF/TLS 終端/ルーティング/パスベース転送を担当。 | パブリック IP あり(唯一の外部入口) |
| API Management(内部モード) | API の公開・認証・レート制限などを担当する API ゲートウェイ。VNet 内のみ到達可能。 | パブリックエンドポイントなし(プライベート) |
| Function App | ビジネスロジックを実装するサーバーレス関数。APIM からのみアクセスさせる。 | VNet 統合+プライベートエンドポイントで外部非公開 |
典型的な通信フローは次のとおりです。
- クライアントが
https://api.example.co.jp/v1/ordersに HTTPS リクエストを送信 - DNS が
api.example.co.jpを Application Gateway のパブリック IP に名前解決 - Application Gateway が TLS を終端し、パスルールに基づいて APIM(プライベート IP) にリクエストを転送
- APIM がポリシーを適用(認証・検証・変換・ログなど)し、バックエンドの Function App にルーティング
- Function App が処理を行い、レスポンスを APIM → App GW → クライアントに返却
この流れの中で、クライアントが意識するのは「App Gateway の公開 URL だけ」 という点が重要です。
外部クライアントに渡すべきエンドポイント
外部公開の観点で最も迷いやすいのが「どの URL をクライアントに教えるか」です。構成が複雑になるほど、APIM の URL や Function の URL をそのまま伝えたくなりますが、それは NG です。
クライアントに渡すべき URL は、以下のように Application Gateway にバインドした独自ドメイン です。
https://api.example.co.jp/v1/ordershttps://api.example.co.jp/v1/customershttps://api.example.co.jp/v2/orders(バージョニング時)
一方で、次のような URL はクライアントに渡しません。
https://my-apim.azure-api.net/v1/orders(APIM の FQDN やプライベートドメイン)https://my-function-app.azurewebsites.net/api/orders(Function App の FQDN)https://<プライベート IP>/v1/orders(IP 直指定)
理由はシンプルで、
- 外部公開ポリシーを守る(APIM・Function はあくまで内部リソース)
- アーキテクチャ変更をクライアントに隠蔽できる(裏側を差し替えても URL を変えずにすむ)
- DNS・証明書・WAF・監査などの集中管理が可能
というメリットがあるからです。クライアントから見えるのは 「一枚岩の API サービス」 であり、裏側に App GW・APIM・Function App など複数レイヤーが存在することは意識させません。
DNS と証明書設計のポイント
次に、外部公開でつまずきやすい DNS と証明書まわりの設計を整理します。
公開 DNS の設定(必須)
インターネット向けの公開 DNS には、次のような A レコードを登録します。
| レコード種別 | 名前 | 値 | 説明 |
|---|---|---|---|
| A | api.example.co.jp | Application Gateway のパブリック IP | クライアントからのトラフィックはすべて App GW に集約される |
これにより、クライアントが https://api.example.co.jp にアクセスすると必ず App GW を通るようになります。
スプリット DNS(推奨パターン)
App GW から APIM に HTTPS 再暗号化で転送する場合、SNI(Server Name Indication)と証明書の CN/SAN を正しく合わせる必要があります。そのため、VNet 内から api.example.co.jp を引いたときに、APIM のプライベート IP に名前解決されるような「スプリット DNS」構成が有効です。
| 環境 | 名前解決結果 | 用途 |
|---|---|---|
| インターネット(外部) | api.example.co.jp → App GW のパブリック IP | クライアントから App GW への入口 |
| VNet 内(App GW から APIM を引くとき) | api.example.co.jp → APIM のプライベート IP | App GW から APIM へのバックエンド接続で SNI/証明書を揃える |
このようにしておくと、App GW のバックエンド設定で「ホスト名:api.example.co.jp」と指定した場合でも、VNet 内では APIM のプライベート IP に解決され、証明書の CN と SNI が綺麗に揃った状態 で TLS 通信が行えます。
証明書の基本ルール
- Application Gateway のフロントエンド リスナー:
api.example.co.jpの 公開証明書 をバインド - App GW → APIM の通信:
バックエンド HTTP 設定で HTTPS を利用し、APIM 側の証明書を信頼ルートに登録(ピアリングが必要な場合は Key Vault 統合も検討) - APIM のカスタムドメイン:
api.example.co.jpをそのまま使うか、内部用の FQDN(例:internal-api.example.local)を使い、App GW 側で Host ヘッダーを上書き
どのパターンを選ぶにしても、「リクエスト時の Host ヘッダーと証明書の CN/SAN が矛盾しないこと」を必ず確認してください。
Application Gateway の設定手順と注意点
ここからは具体的な構成手順を見ていきます。まずは Application Gateway 側の設定です。
フロントエンドとリスナー
- フロントエンド IP 構成で パブリック IP アドレス を割り当て
- リスナーを作成し、以下を設定
- プロトコル:HTTPS
- ホスト名:
api.example.co.jp - 証明書:
api.example.co.jpの証明書(PFX)
バックエンドプール
- バックエンドプールのターゲットとして、APIM のプライベート IP、もしくはプライベート FQDN を登録
- 内部モード APIM の場合、サブネット内のプライベート IP が割り当てられているはずなので、それを指定
HTTP 設定とホストヘッダー
バックエンドへの HTTP 設定では、次の点を押さえます。
- プロトコル:HTTPS
- ポート:
443 - サーバー証明書の検証:有効(必要に応じて信頼ルートを構成)
- ホスト名の設定:
- APIM 側のカスタムドメインに合わせて「バックエンドのホスト名を上書き」
- あるいは「バックエンドのホスト名を使用」にしてスプリット DNS で解決させる
ヘルスプローブの設定
Application Gateway から APIM へのヘルスチェックには、APIM 既定のステータスエンドポイントを利用するのが定番です。
- パス:
/status-0123456789abcdef - メソッド:GET
- ホストヘッダー:APIM のホスト名(例:
api.example.co.jp)
このプローブが Healthy にならない場合、SNI/証明書不整合や DNS 解決、ネットワークセキュリティグループ(NSG)、ユーザー定義ルート(UDR)などの問題が疑われます。
ルールとパスベースルーティング
最後にルールを設定します。
- リスナー:
api.example.co.jpの HTTPS リスナー - バックエンドターゲット:APIM のバックエンドプール
- HTTP 設定:前述の HTTPS 設定
- ルールの種類:パスベース推奨
/v1/* → APIM/v2/* → APIM の別 API(将来用)
パスベースにしておくと、将来 BFF(Backends for Frontends)やバージョン違い API などを追加するときにも柔軟に運用できます。
API Management(内部モード)の設計と実装
次に APIM 側のポイントを整理します。ここでは「内部モード」で VNet に統合されている前提です。
内部モードと VNet 統合
- APIM を内部モードで作成すると、インターネット向けのパブリックエンドポイントは持たず、指定したサブネット内にプライベート IP が割り当てられます。
- App GW とは同じ VNet またはピアリングされた VNet 内で接続されます。
- VNet 内での DNS 解決が重要になるため、後述のプライベート DNS ゾーンとセットで考えると構成がスムーズです。
カスタムドメインの設定
APIM には「ゲートウェイ」「管理ポータル」など複数のホスト名がありますが、クライアントトラフィックに関係するのはゲートウェイドメインです。
- ゲートウェイドメインに
api.example.co.jpを割り当てる - あるいは内部用のドメイン(例:
internal-api.example.local)を割り当て、App GW 側で Host ヘッダーを上書きする
App GW の「バックエンドのホスト名」と APIM のカスタムドメイン設定がずれていると、TLS ハンドシェイクでエラーになりがちなので注意してください。
バックエンドとして Function App を登録
APIM から Function App を呼び出す方法は大きく分けて 2 パターンあります。
- APIM から Function App を直接インポート
- Azure ポータルの「+ Add API」→「Function App」から関数を選択
- 関数キーなどを自動で登録してくれるので簡単
- OpenAPI(Swagger)定義からインポート
- Function App が OpenAPI 定義を持っている場合に有効
- 既存の HTTP API をまとめて APIM に取り込める
どちらの方法でも、APIM のバックエンド URL は Function App のプライベートエンドポイントの FQDN(例:my-funcapp.privatelink.azurewebsites.net)を使う構成が推奨です。
プライベート DNS の構成(Function 用)
Function App にプライベートエンドポイントを作成すると、通常は以下のようなプライベート DNS ゾーンを作ります。
privatelink.azurewebsites.net
このゾーンを APIM が存在する VNet にリンクしておくことで、APIM から Function App の FQDN が正しくプライベート IP に解決されます。これを忘れると、APIM から Function への名前解決が失敗し、タイムアウトに見える形でエラーになります。
関数キーを Named value に格納し、ポリシーで付与
Function App の認証に使う「関数キー」は絶対にクライアントに渡さず、APIM 側で安全に管理します。
- APIM の「Named values」に Function App の関数キーを登録(シークレットとしてマスク)
- API または Operation のポリシーで、その Named value を使ってバックエンドにヘッダーを付与
代表的なポリシー例は次のとおりです。
<policies>
<inbound>
<base />
<set-header name="x-functions-key" exists-action="override">
<value>{{func-key-nv}}</value>
</set-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
{{func-key-nv}} は Named value 名です。こうしておけば、クライアントから見えるのは APIM の認証方式(サブスクリプションキーや JWT)だけで、Function のキーは完全に隠蔽できます。
Function App 側のネットワークとセキュリティ設計
次に、Function App 側の設定です。ここが甘いと「せっかく APIM 経由にしたのに、Function のパブリック URL が開きっぱなし」という残念な状態になってしまいます。
VNet 統合とプライベートエンドポイント
- Function App に対して VNet 統合 を設定し、バックエンドのアウトバウンド通信を VNet 経由にする
- さらに プライベートエンドポイント を作成し、Function App の HTTP エンドポイントへの インバウンド通信も VNet 内に限定 する
このとき自動的に、前述の privatelink.azurewebsites.net との関連付けが生成されます。
アクセス制限(Access Restrictions)の設定
Function App 側でアクセス制限を設定し、APIM からのトラフィックのみ許可するのがベストプラクティスです。
- 許可ルール:APIM のサブネット(または APIM のプライベート IP)からのアクセスを Allow
- 拒否ルール:それ以外のネットワークを Deny
これにより、万が一 DNS やルーティング設定が誤っていても、APIM 経由でないアクセスは Function App に届かなくなります。
認証の責任分担
認証・認可の責任分担は次のようにすると設計が明確になります。
- APIM 側:外部クライアント向けの認証・認可(サブスクリプションキー、JWT、IP 制限など)
- Function 側:APIM からの内部トラフィックだけを想定し、関数キーなどの最小限の認証
この二段構えによって、機能面は APIM で素早く変えつつ、Function 側は比較的シンプルな構成に保ちやすくなります。
Postman でのテスト方法と認証ヘッダー
ここからは、実際に Postman などのクライアントでテストするときの具体的な設定例を見ていきます。
A. APIM のサブスクリプションキー方式(もっとも簡単)
APIM を使った最もシンプルな方法は、サブスクリプションキーを利用する方式です。
- リクエスト URL:
GET https://api.example.co.jp/v1/orders - ヘッダー:
Ocp-Apim-Subscription-Key: <APIM サブスクリプションキー>
このとき、バックエンドの Function App に必要な関数キーは、前述のように APIM のポリシーで自動的に付与されます。クライアント側では Function の存在を意識する必要はありません。
B. Microsoft Entra ID(旧 Azure AD)での JWT 認証(ゼロトラスト推奨)
本番環境では、より厳格な認証として Microsoft Entra ID(旧 Azure AD)ベースの JWT を使うパターンが推奨です。
1. Postman 側のトークン取得設定
- Postman の Auth タブで「OAuth 2.0」または「Bearer Token」を選択
- 以下の情報を設定
- 認可エンドポイント&トークンエンドポイント:テナントの OAuth2 エンドポイント
- クライアント ID / クライアントシークレット:発行済みのアプリ登録情報
- スコープ / リソース:APIM 上の API に対応するアプリ ID URI(例:
api://<app-id>/default)
- 「Get New Access Token」を実行して JWT を取得
2. API 呼び出し
- リクエスト URL:
https://api.example.co.jp/v1/orders - ヘッダー:
Authorization: Bearer <取得したアクセス トークン> - 必要に応じてサブスクリプションキー:
Ocp-Apim-Subscription-Key: <キー>
APIM のポリシーでは、JWT の検証(iss、aud、exp、scp など)を行い、条件に合わないトークンは 401/403 で遮断するようにします。
C. 関数キー直接付与(テスト限定・原則非推奨)
どうしても Function App を直接テストしたい場合、次のように関数キーを直接指定することもできます。
- クエリストリング:
?code=<関数キー> - またはヘッダー:
x-functions-key: <関数キー>
ただし、本番運用でクライアントに関数キーを渡してしまうと、APIM を迂回した直接アクセスを招く危険があります。あくまで開発時のスポットテストに留め、本番では APIM が関数キーを付与する方式 に統一してください。
Postman テスト時のチェックポイント
- DNS:
api.example.co.jpが App GW のパブリック IP に解決されているか - 証明書:自己署名証明書を使っている場合は Postman の「証明書検証を無効化」を一時的にオンにして切り分け
- 認証ヘッダー:サブスクリプションキーや Bearer トークンを付け忘れていないか
- レスポンスコード:
- 401/403 → 認証・認可の問題(APIM)
- 502/504 → バックエンド到達不可(App GW-APIM 間、APIM-Function 間)
よくあるトラブルとチェックリスト
ここでは、実際の構築で遭遇しやすい「ハマりポイント」をチェックリスト形式でまとめます。
| 症状 | 疑うべきポイント | 確認方法 |
|---|---|---|
| App GW のバックエンド状態が Unhealthy | SNI/証明書不整合、APIM の DNS 解決ミス | ヘルスプローブのホストヘッダーと APIM の証明書 CN/SAN を比較 |
| Postman から 502 Bad Gateway | APIM へのルーティング設定ミス、ポート誤り | App GW のアクセスログと APIM の診断ログを照合 |
| APIM から Function への呼び出しだけがタイムアウト | Function のプライベート DNS ゾーン未設定、NSG/UDR でブロック | APIM のサブネットから nslookup/tcpping などで確認 |
| ブラウザから CORS エラー | APIM 側の CORS 設定不足 | APIM の CORS ポリシーとクライアントオリジンの整合を確認 |
| JWT を付けているのに 401 | aud(リソース)不一致、トークン期限切れ、時刻ずれ | JWT をデコードしてクレームを確認、サーバー時刻を同期 |
最後に、構成全体を通してのチェックリストをまとめます。
- App GW の SNI/Host ヘッダー が APIM の証明書と一致しているか
- App GW → APIM の ヘルスプローブ(
/status-0123456789abcdef)が Healthy か - APIM と Function の FQDN が プライベート DNS で正しく解決できるか
- Function App の アクセス制限 が APIM 経由のトラフィックのみ許可になっているか
- APIM の CORS / リクエストサイズ / タイムアウト が要件に合っているか
- App GW の WAF 有効化、APIM の レート制限・スロットリング が適切か
- URL 設計(
/v1/や/v2/のようなバージョン・ドメイン別パス)が一貫しているか
設計パターンのバリエーションと発展例
本記事で紹介したパターンはあくまで一例であり、要件によって派生パターンも考えられます。
環境別のドメイン分割
- 本番:
https://api.example.co.jp/ - 検証:
https://api-stg.example.co.jp/ - 開発:
https://api-dev.example.co.jp/
App GW・APIM・Function App を環境ごとに分けつつ、クライアントには環境別のドメインだけを意識させる設計ができます。
パスベースで複数バックエンドを束ねる
App GW や APIM のパスベースルーティングを活用すると、モノリシックな API からマイクロサービスへの移行もスムーズになります。
/v1/orders→ Function App A/v1/customers→ Function App B/v1/payments→ 別サブスクリプションの App Service
いずれの場合も、クライアント側からは単一の API ドメインに見える ため、API の進化を裏側で柔軟に行えるのが大きなメリットです。
自社認証基盤との連携
Microsoft Entra ID の代わりに、社内の認証基盤(IdP)と連携させるパターンもあります。この場合は、
- IdP で OIDC / SAML などを利用してトークンを発行
- APIM でトークンを検証するポリシーを設定
といった構成を取ります。いずれにせよ、APIM で認証を終端し、Function App にはトークンをそのまま流さない という発想を持つと、構成がシンプルでセキュアになります。
まとめ
本記事では、
- クライアント → Application Gateway(パブリック) → APIM(内部) → Function App(プライベート)
という構成で、Function App を安全かつ柔軟に外部公開する方法を解説しました。
- 外部クライアントに渡すべき URL は、Application Gateway に割り当てた独自ドメインの HTTPS URL だけ(例:
https://api.example.co.jp/v1/orders) - App GW が公開入口、APIM が認証とポリシー適用、Function App が実装という役割分担を明確にする
- DNS・証明書・SNI・プライベート DNS・アクセス制限をセットで設計することが安定運用の鍵
- Postman からのテストでは、サブスクリプションキーまたは Microsoft Entra ID の Bearer トークンを付与して App GW の URL を叩くだけでよい
- Function の関数キーは APIM の Named value に保存し、ポリシーでバックエンドにのみ付与することで、クライアントに晒さない
この方針を押さえておけば、今後 API が増えても同じパターンで拡張でき、インターネット公開ポリシーやゼロトラストの要件にも対応しやすくなります。新規構築はもちろん、既存システムのリプレースや段階的なクラウド移行の際にも、ぜひ本記事の設計指針を参考にしてみてください。

コメント