はじめに
Azure App Service を社外向けに公開したいけれど、「Public IP は持たせたくない」「IP 制限ではなくユーザー単位で認証・認可をかけたい」というご相談を頂くことがあります。
このようなケースで使える選択肢の 1 つが Microsoft Entra Application Proxy(以下、App Proxy) です。本記事では App Service の publicNetworkAccess = Disabled(パブリックアクセス無効)の状態で、App Proxy 経由で社外ブラウザからアクセスできる構成を実際に検証してみました。実際に E2E で疎通まで確認できたので、構成と手順、ハマりどころを残しておきます。
公式ドキュメントは以下です。
- ネットワーク トポロジ: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/application-proxy-network-topology
- ヘッダーベースの SSO 設定: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/application-proxy-configure-single-sign-on-with-headers
※ 記事作成の補助に GitHub Copilot を活用しています。
目的
以下の 4 点を同時に満たす構成を作ることが今回のゴールです。
| 要件 | 採用したアプローチ |
|---|---|
| インバウンドのパブリックアクセスをゼロにしたい | App Service の publicNetworkAccess = Disabled + Private Endpoint |
| 社外ユーザーがブラウザだけでアクセスしたい | Entra Application Proxy(リバーストンネル方式) |
| 認証を Entra ID で一元管理したい | App Proxy の Pre-Authentication 機能 |
| アプリ側でもユーザーを識別・制御したい | App Proxy が転送するヘッダーを使ったアプリ内認可 |
なお、本来 App Service を社外公開するのであれば、Application Gateway(+ WAF)や Front Door などを前段に置く構成が望ましいケースが多いかと思います。今回はそもそも インバウンド向けのパブリック IP を一切持ちたくない という要件があったため、あえて App Proxy を使った構成を検証しています。後述の通り、この構成でもパブリック IP は残りますが、それは Connector VM のアウトバウンド通信用 のものに限定されます。
前提知識
Entra Application Proxy とは
App Proxy は、社内・プライベートに置かれた Web アプリを 顧客側のインバウンドポートを 1 つも開けずに 社外公開できるリバースプロキシサービスです。
仕組みとしては、お客様の VNet 内に「Connector」と呼ばれるエージェントを Windows Server VM 上にインストールし、Connector から Microsoft クラウドに対して outbound 443 のみ で接続を維持します(リバーストンネル)。社外ユーザーからのリクエストはこのトンネルを通ってバックエンドに届きます。
公式のネットワーク トポロジはこちら。
社外ユーザー ─HTTPS→ *.msappproxy.net(Microsoft 管理)
│ リバーストンネル (outbound 443 のみ)
Connector VM(顧客 VNet 内)
│ Private Network
App Service(publicNetworkAccess = Disabled)
ライセンス要件
App Proxy の利用には Entra ID P1 / P2 のライセンスが必要です(無料 SKU では使えません)。
構成
全体構成
リソース一覧
| 種別 | 役割 | パブリック面 |
|---|---|---|
| App Service | 業務アプリ本体 |
なし (publicNetworkAccess = Disabled) |
| Private Endpoint | App Service への VNet 内接続口 | なし |
Private DNS Zone (privatelink.azurewebsites.net) |
Connector VM からの名前解決を Private IP に向ける | なし |
| 仮想ネットワーク + サブネット 3 つ | ネットワーク基盤 | なし |
| Connector VM (Windows Server 2022) | App Proxy Connector ホスト | なし(Private IP のみ) |
| NAT Gateway | Connector の outbound 443 出口 | あり(送信専用) |
| Azure Bastion | Connector VM への管理アクセス | あり(管理専用) |
認証・認可の設計
ここが今回検証で一番悩んだポイントです。App Proxy の Pre-Authentication と App Service の Easy Auth(組み込み認証) はそれぞれ独立してオン/オフできるため、組み合わせで 4 パターン存在します。
パターン比較
| # | App Proxy Pre-Authentication | App Service Easy Auth | 認証の担当 | 評価 |
|---|---|---|---|---|
| ① | あり (Entra ID) | なし | App Proxy が完全に担当 | 本記事の構成(推奨) |
| ② | なし (Passthrough) | あり (Entra ID) | Easy Auth が担当 | 代替可。ただし App Proxy 側の条件付きアクセスは効かない |
| ③ | あり (Entra ID) | あり (Entra ID) | 二重認証 | 非推奨。設定ミスで陥りやすい罠 |
| ④ | なし (Passthrough) | なし | 認証なし | アプリ自前認証がある場合のみ |
パターン①(推奨)— App Proxy Pre-Auth のみ
[社外ユーザー] → App Proxy(Entra ID 認証)→ Connector → App Service(Easy Auth 無効)
↑ここで認証・認可を完結
App Proxy が Entra ID によるサインインを強制するため、未認証・未割り当てのリクエストはバックエンドに届きません。アプリ側はヘッダーを読むだけで済み、認証ロジックを実装する必要がありません。
サインイン済みユーザーの情報は、ヘッダーベース SSO の設定で以下のような HTTP ヘッダーとしてバックエンドに転送されます。
| ヘッダー名 | ソース属性 | 内容 |
|---|---|---|
X-AppProxy-UPN |
user.userprincipalname |
ユーザー プリンシパル名 |
X-AppProxy-Email |
user.mail |
メールアドレス |
X-AppProxy-OID |
user.objectid |
Entra ID オブジェクト ID(GUID) |
ヘッダー名は任意に決められます。アプリ側はこれらのヘッダーを読むだけで、認証済みユーザーの情報を取得できます。
ヘッダーベース SSO の設定方法は公式手順をご参照ください。
パターン③(要注意)— 二重認証
[社外ユーザー] → App Proxy(Entra ID 認証)→ Connector → App Service(Easy Auth 有効)
↑1回目 ↑2回目(競合)
App Proxy と Easy Auth の両方が独立してトークン検証を要求するため、認証ループや二重サインインが発生する場合があります。Easy Auth は Authorization ヘッダーを書き換えるため、App Proxy のトークンと競合することもあります。
App Proxy を導入する際は、App Service 側の認証機能(Easy Auth)は必ず無効化 することがポイントです。
認証フロー全体
構築手順
1. ネットワーク基盤のデプロイ
VNet とサブネットを作成します。
-
snet-connector:Connector VM 配置用 -
snet-pe:App Service 用 Private Endpoint 配置用 -
AzureBastionSubnet:Bastion 用(/26 以上)
加えて、Connector VM の outbound 443 を集約するための NAT Gateway を snet-connector に関連付けます。
2. App Service のパブリックアクセス無効化
az webapp update -g <リソースグループ> -n <アプリ名> \
--set publicNetworkAccess=Disabled
これで publicNetworkAccess が Disabled になり、インターネットからの直接アクセスは遮断されます。ポータル上も Networking → Public network access = Disabled と表示されます。
3. Private Endpoint と Private DNS Zone
App Service 用の Private Endpoint を snet-pe に作成し、privatelink.azurewebsites.net の Private DNS Zone を VNet にリンクします。これで Connector VM から <アプリ名>.azurewebsites.net を引いたときに、Private IP(例: 10.50.1.4)が返るようになります。
# Connector VM 上で名前解決を確認
nslookup <アプリ名>.azurewebsites.net
# → Address: 10.50.1.4 (PE の Private IP)を返すこと
公式手順はこちら。
4. Connector VM の作成
snet-connector に Windows Server 2022 の VM をデプロイします。Public IP は付与しません。NSG は inbound すべて Deny、outbound 443 を許可します。管理アクセスは Azure Bastion 経由で行います。
VM 上で nslookup <アプリ名>.azurewebsites.net を実行し、Private IP が返ってくることを確認します。
5. App Proxy Connector のインストール
Entra 管理センターから Connector のインストーラをダウンロードし、Connector VM 上で実行します。インストール時にグローバル管理者でサインインすると、Connector が Entra テナントに登録されます。
- Entra 管理センター → Application Proxy
正常にインストールされると、Connector のステータスが Active になります。
補足(条件付きアクセスでハマった場合): Connector のインストーラは内部で WebView2 によるサインイン画面を出します。このダイアログは FIDO キーや証明書ベース MFA 等の条件付きアクセスポリシー下では完了できないことがあります。
その場合は、サービスだけ先に静かにインストール(/q)した上で、別端末でaz account get-access-token --resource https://proxy.cloudwebappproxy.net/registerappでトークンを取得し、VM 上のRegister-AppProxyConnector -AuthenticationMode Token -Token <SecureString>で登録するという回避策が使えます。
6. Enterprise Application としてアプリを公開
Entra 管理センター → Enterprise applications → New application → On-premises application から、以下の項目を設定します。
| 項目 | 設定値 |
|---|---|
| Internal URL | https://<アプリ名>.azurewebsites.net/ |
| External URL |
https://<アプリ名>-<テナント名>.msappproxy.net/(既定) |
| Pre-Authentication | Microsoft Entra ID |
| Connector Group | 作成した Connector グループ |
| Translate URLs in Headers | Yes |
その後、Users and groups からアプリにアクセスを許可するユーザーを割り当て、Single sign-on で前述のヘッダーマッピングを設定します。
7. 動作確認
社外ネットワーク(テザリング等)からブラウザで External URL にアクセスし、以下の動作を確認します。
| シナリオ | 期待動作 |
|---|---|
| 未サインインで外部 URL にアクセス | Entra サインイン画面にリダイレクト |
| 割り当て済みユーザーでサインイン | アプリ画面が表示され X-AppProxy-UPN ヘッダーを確認できる |
| アプリ未割り当てユーザーでサインイン | App Proxy レベルで拒否(バックエンドに届かない) |
社外から直接 azurewebsites.net にアクセス |
接続不可(Public アクセス無効のため) |
実際にアプリを開くと、X-AppProxy-UPN / X-AppProxy-Email / X-AppProxy-OID ヘッダーがアプリに届いていることと、判定結果が ALLOWED になっていることが見えます。
ハマりどころ・注意点
Header-based SSO の保存に P1 ライセンス保有者のアサインが必要
今回いちばんハマったのがこれです。Single sign-on でヘッダーマッピングを設定して保存しても、再度開くと SSO 方式が「Disabled」に戻ってしまう という現象が発生しました。
原因は、対象アプリに Entra ID P1 ライセンスを持つユーザーが 1 人もアサインされていなかった ことでした。Header-based SSO は P1 機能のため、保存時に「P1 を持つ割り当て済みユーザーが 1 人以上いること」がチェックされるようです。
手順としては 「ユーザー割り当て → SSO 設定保存」の順 で進めるのが安全です。
Azure サブスクリプションと Entra テナントが別組織でも OK
今回の検証は、Azure リソースは A サブスクリプション、Entra / App Proxy 設定は B テナント、という構成で実施しました。Connector を登録するテナントと Enterprise App を作成するテナントが 同一 であれば、Azure サブスクリプションと Entra テナントは別の組織でも構成可能です。マルチテナント運用や、リソース管理用テナントと従業員 ID テナントが分離している環境でも導入できます。
App Service の SKU クォータ
当初 Japan East で構築を試みたのですが、Free / PremiumV3 の SKU クォータが 0 で App Service Plan の作成に失敗しました。本番ではリージョン選定の前にクォータ確認を行うのが安全です。
Easy Auth の二重有効化
前述の通り、App Proxy の Pre-Authentication を使う場合は App Service の認証機能(Easy Auth)を必ず無効化します。両方有効にするとトークンが競合してハマります。
残存するパブリック IP
「パブリックアクセスゼロ」と言いつつも、以下の用途でパブリック IP が残ります。
- NAT Gateway:Connector VM の outbound 443(App Proxy クラウドへ)の送信元 IP
- Azure Bastion:管理者の RDP アクセス用
どちらもアプリの inbound 公開には使われませんが、構成上は残ります。Bastion については Private-only deployment(プレビュー)でパブリック IP を不要にできますが、その場合は管理者端末から VNet までのプライベート接続(ExpressRoute / VPN Gateway)が別途必要です。
App Proxy の機能制限
WebSocket、1GB 超レスポンス、長時間接続(タイムアウト 4 時間)など、App Proxy ではサポートされない通信があります。リアルタイム性の高いアプリは事前確認が必要です。
ヘッダー偽装リスク
X-AppProxy-* ヘッダーは単なる HTTP ヘッダーなので、App Proxy を経由しない経路から偽装されると認可をすり抜ける可能性があります。publicNetworkAccess = Disabled で直接アクセスを完全に遮断することが必須の防御策となります。
まとめ
App Service を Public IP なしで社外公開する手段として、Entra Application Proxy は非常に有効な選択肢でした。今回は E2E 検証として、未認証アクセス / 許可ユーザーアクセス / 許可外ユーザーアクセス / 直接アクセス遮断 の 4 つのシナリオをいずれも期待通り動かすことができました。特に以下の条件に当てはまる場合は検討する価値があると思います。
- インバウンドのパブリックアクセスを完全に遮断したい
- 認証を Entra ID で一元管理し、条件付きアクセスを効かせたい
- アプリ側に認証ロジックを実装したくない(または既存アプリを改修したくない)
逆に、WebSocket を多用するアプリや、1GB を超えるレスポンスを返すアプリには向きません。要件に応じて Front Door + WAF + Private Link 構成などとの比較検討をおススメします。
認証・認可方式の組み合わせは複数あり、特に App Proxy と Easy Auth の二重有効化はハマりやすいポイントなので、最初に設計の絵を描いてから構築するのが近道かと思います。
参考リンク
- Application Proxy 概要: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/overview-what-is-app-proxy
- ネットワーク トポロジ: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/application-proxy-network-topology
- ヘッダーベース SSO の構成: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/application-proxy-configure-single-sign-on-with-headers
- オンプレミス アプリの公開手順: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/application-proxy-add-on-premises-application
- App Service の Private Endpoint: https://learn.microsoft.com/ja-jp/azure/app-service/networking/private-endpoint
- App Service のパブリック アクセス無効化: https://learn.microsoft.com/ja-jp/azure/app-service/overview-access-restrictions
- Application Proxy FAQ / 制限事項: https://learn.microsoft.com/ja-jp/entra/identity/app-proxy/application-proxy-faq





