Azure Application Gateway(WAFv2)ヘルスプローブでAzure Storage(Private Endpoint)を2xxにする設定

Azure Application Gateway(WAFv2)配下にAzure Storageを置き、パブリックアクセス無効・Private Endpointのみ・匿名/SASなしという堅牢構成にすると、正常性プローブが403/409になりバックエンドがUnhealthyになりがちです。本記事では2xxを返す現実的な設計と設定手順、落とし穴を整理します。

目次

前提となる構成と「なぜプローブが落ちるのか」

今回の前提は次のとおりです。

  • バックエンドは Azure Storage アカウント(Blob)
  • クライアント→Storage への入口として Azure Application Gateway(WAFv2) を利用
  • Storage 側は パブリック ネットワーク アクセス無効、プライベート エンドポイントのみ
  • 匿名アクセス無効(「Allow Blob public access」を無効にしている/コンテナーを非公開にしている等)
  • SAS トークンも使わない(もしくは組織ポリシーで禁止)

この状態で Application Gateway のバックエンド正常性プローブ(ヘルス プローブ)を HTTP/HTTPS で投げると、プローブが以下の理由で失敗しやすくなります。

起きる現象典型的な原因よく見るステータス
到達できずタイムアウトPrivate Endpoint/DNS/ルート/NSG などネットワーク要因で Storage のプライベート IP に到達できていない502/タイムアウト(AppGW 側)
到達はするが Unhealthy のままStorage が認証を要求するのに、プローブが認証ヘッダーやクエリを付与しない(または Host ヘッダー不整合)403/409/400
Host ヘッダーが合わずに失敗バックエンドに IP を指定していて SNI/Host ヘッダーが Storage の証明書名と一致しない400/SSL 失敗

ポイントは、Application Gateway のプローブは基本的に 「指定した URL に対して GET を投げ、返ってきたステータスで正常性を判定する」という仕組みであることです。Storage 側が「匿名不可・SAS不可・Public 不可」のままだと、“正しい認証” を伴わないプローブは 2xx になりにくいのが本質です。

さらに、Storage を HTTPS で叩く場合は 証明書の名前(ホスト名)にも厳格です。バックエンドに Private Endpoint の IP を直接入れていると、SNI/Host が噛み合わず失敗することがあるため、ホスト名上書きは必須項目だと考えてください。

まず切り分けるべきは「ネットワークの到達性」

いきなりプローブ設定に入る前に、Application Gateway から Storage へ プライベート エンドポイント経由で到達できているかを先に潰すと、無駄な試行錯誤が減ります。

確認観点チェックリスト

  • Application Gateway が存在する VNet から、Storage の FQDN が プライベート IP に名前解決できている
  • 強制トンネリングや UDR により、Storage 宛トラフィックが意図せず別経路へ流れていない
  • カスタム DNS を使っている場合、privatelink.blob.core.windows.net(必要に応じて privatelink.web.core.windows.net など)を解決できる
  • Application Gateway のサブネット側で、宛先 443 をブロックする NSG ルールが入っていない

同一 VNet 内のテスト VM での検証例

Application Gateway と同じネットワーク(同一 VNet か、適切にピアリングされた VNet)に、検証用 VM を一時的に置けるなら、次の確認が一番早いです。

  1. nslookup <ストレージ名>.blob.core.windows.net を実行し、プライベート IP が返ることを確認
  2. Web エンドポイントを使う予定なら nslookup <静的サイトのホスト名> でも同様に private 側を引くことを確認
  3. 既知のパスに対して curl -I https://<ホスト名>/<パス> を実行し、TLS 接続と HTTP 応答を確認

この段階で名前解決・到達性が崩れていると、プローブに何を設定しても Unhealthy になります。逆に、ここが固まっていれば、次は「2xx を返すエンドポイント設計」に集中できます。

2xx を返すための代表的な解決パターン

今回の制約(匿名不可、SAS不可、Public 不可)をそのまま守ろうとすると、Application Gateway のプローブだけで 2xx を返すのは難易度が上がります。実務では、次のいずれかに落ち着くことが多いです。

パターン2xx を返す仕組みメリット注意点向いているケース
静的 Web サイト($web)にヘルスページ$web の固定ファイルが常に 200 を返す構成がシンプル/プローブが安定匿名読み取りを「どこまで許容するか」の整理が必要(ただし Private Endpoint 前提なら閉域に寄せられる)最短で安定させたい/運用負荷を下げたい
ヘルスチェック専用コンテナーのみ匿名特定コンテナー内の固定ファイルが 200匿名範囲を最小化できるアカウントの「Allow Blob public access」や組織ポリシー次第で不可静的 Web サイトを使いにくい/匿名範囲をさらに狭めたい
SAS をプローブに付与SAS 付き URL で 200匿名を開けずに 200 を返せるSAS の漏えい・期限管理・ローテーションが課題/「SAS 禁止」要件と衝突しやすいSAS を許容でき、運用で管理できる
ヘルスプロキシ(中継)を用意AppGW→中継は 200、中継→Storage は認証付きで疎通確認Storage を完全に閉域&匿名/SAS なしを維持できる追加コンポーネントが必要(Function/Container 等)セキュリティ要件が厳格で、匿名/SAS を絶対に避けたい

静的 Web サイト機能でヘルス プローブを成功させる

「プローブが 200 を返す URL を用意する」という意味で、静的 Web サイト($web)を使うのは非常に現実的です。質問事例でも、この方法で Unhealthy を解消できたケースが多いです。

設計の考え方

  • プローブ先は 必ず存在する固定ファイルにする(例:healthz.html)
  • ファイルの内容はシンプルでよい(例:OK の1行)。必要ならデプロイ日時などを埋め込む
  • 「匿名で読める」こと自体が気になる場合でも、Public network access 無効 + Private Endpoint を組み合わせれば、インターネットからは到達できない構成に寄せられる

なお、ストレージ アカウントで 「Allow Blob public access」 を無効にしている場合、静的 Web サイト機能の有効化や動作が制限されることがあります。組織ポリシーで厳格に禁止されている環境では、後述の「ヘルスプロキシ」方式の方が説明しやすいこともあります。

静的 Web サイトのエンドポイントは二種類ある

静的 Web サイトを使う場合、ヘルスチェックで叩く先は大きく2パターンあります。

プローブ先例特徴Private Endpoint の要件
Web エンドポイント(静的サイト専用)https://<ストレージ名>.<任意>.web.core.windows.net/healthz.html静的 Web サイト向け。基本的に匿名読み取りで 200 を返しやすい「web」サブリソース用の Private Endpoint と DNS(privatelink.web.core.windows.net)が必要になることが多い
Blob エンドポイントで $web を参照https://<ストレージ名>.blob.core.windows.net/$web/healthz.htmlBlob と同じ経路。環境によっては匿名で 200 を返すが、コンテナー公開設定やポリシーの影響を受けやすいblob 用の Private Endpoint と DNS(privatelink.blob.core.windows.net)で到達できる

迷ったら、まずは ポータルの「静的ウェブサイト」ブレードに表示される「プライマリ エンドポイント」(= Web エンドポイント)を使うのが安全です。組織ポリシーや Private Endpoint のサブリソース選択により使えない場合は、Blob エンドポイント側の $web を使う落としどころを検討します。

設定手順(Storage 側)

  1. Storage アカウントで Blob サービス → 静的ウェブサイト を有効化する
  2. インデックス ドキュメント名に index.html を指定(ヘルス専用なら healthz.html を置いてもOK)
  3. $web コンテナーに、ヘルスチェック用のファイルをアップロードする(例:healthz.html)

ヘルスチェック用ファイルの例です。

OK

Private Endpoint と DNS の注意点(Web エンドポイントを使う場合)

Public network access を無効にしている構成では、Web エンドポイントもインターネットからは到達できません。VNet 内からアクセスさせるには、次のいずれかが必要になります(環境差があります)。

  • Storage の Private Endpoint を 「web」サブリソースで追加作成する
  • Private DNS ゾーン privatelink.web.core.windows.net を作成し、Application Gateway のある VNet にリンクする

このあたりは「同じ VNet の検証 VM で名前解決してみる」と最短で判断できます。Web エンドポイントが public 側に解決されるなら、Private Endpoint/DNS が不足しています。

設定手順(Application Gateway 側:プローブ)

プローブ設定で重要なのは Host ヘッダーと パスです。Storage は要求先のホスト名に敏感なので、ここがズレると 2xx になりません。

項目推奨値(例)意図
プロトコルHTTPSStorage は基本 HTTPS 前提。証明書検証と SNI を意識する
ホスト<静的サイトのホスト名> または <ストレージ名>.blob.core.windows.netStorage の証明書名と一致させる(SNI/Host ヘッダーの整合)
パス/healthz.html または /$web/healthz.html必ず存在する固定ファイルを指定し 200 を取りに行く
許容ステータス200-399(要件が 2xx 固定なら 200 のみに絞る)リダイレクトが入る構成でも落ちにくくする
間隔 / タイムアウト30秒 / 30秒(例)Backend の特性に合わせて調整。短すぎると瞬断で Unhealthy になりやすい

バックエンド プールと HTTP settings の設定例(ここがズレると 2xx にならない)

プローブだけを直しても、バックエンド プールや HTTP settings の Host/SNI がズレていると失敗します。最小構成の例をまとめます。

設定箇所推奨(例)理由
バックエンド プールターゲット:FQDN
値:<ストレージ名>.blob.core.windows.net または <静的サイトのホスト名>
DNS で Private Endpoint の IP を引かせつつ、TLS のホスト名整合(SNI)も取りやすい
HTTP settingsプロトコル:HTTPS / ポート:443
ホスト名:バックエンドから選択(または上書きで Storage のホスト名)
SNI:有効
Storage は証明書名チェックが厳しいため、IP 宛接続でもホスト名を正しく送る
証明書通常は “信頼されたルート CA” で検証(追加の証明書設定は不要なことが多い)Storage の証明書は一般的な公開 CA で発行されているため

バックエンド プールに Private Endpoint の IP を直接入れる方法もありますが、その場合は HTTP settings でホスト名上書きと SNI がより重要になります。まずは FQDN 登録 + Private DNS で成立させる方が運用は安定します。

さらに確実にするための設定のコツです。

  • バックエンド HTTP 設定(HTTP settings)で 「バックエンド アドレスからホスト名を選択」または 「特定のホスト名で上書き」を有効にし、Storage のホスト名を送る
  • バックエンドに IP(Private Endpoint の IP)を入れている場合は、HTTP settings 側で SNI とホスト名の上書きが必須になることが多い
  • 「/」のようなルートに対する応答は環境差が出やすいので、固定ファイルを置いてそこを叩く方が安定する

セキュリティ上の落としどころ

静的 Web サイトは「匿名で 200 が返る」ことが利点ですが、同時に気になる点でもあります。実務上は次の運用でリスクを最小化できます。

  • 公開するのは ヘルスチェック専用の1ファイルのみ(個人情報・業務データを置かない)
  • Public network access は無効のままにし、VNet 内(Private Endpoint)からしか到達できない構成にする
  • ファイル内容に機微情報を入れない(「OK」だけ、もしくは無害な固定文字列)

マネージド ID を使った「認証付きプローブ」を検討する場合

「匿名も SAS も使わず、Azure AD(RBAC)で認可した状態で 2xx を返したい」という発想で、Application Gateway 側にマネージド ID を割り当て、Storage 側でロール付与してプローブする案が検討されることがあります。

ロール付与でよくある誤解

Storage アカウントに対して単に Reader ロールを付与しても、Blob のデータ面(コンテナー/Blob の読み取り)には権限が足りません。データアクセスが必要なら、用途に応じて次のような データ プレーンのロールが必要です。

  • 読み取りだけ:Storage Blob Data Reader
  • 書き込みも含む:Storage Blob Data Contributor など

それでも「AppGW のプローブだけ」で完結しにくい理由

ここが重要です。Storage を Azure AD で認証してアクセスするには、通常 OAuth の Bearer トークンをリクエストに付ける必要があります。Application Gateway のヘルス プローブは、固定のヘッダーを付けることはできても、マネージド ID からトークンを取得して自動更新しながら付与するといった “動的認証” を前提に作られていません。

そのため、マネージド ID を有効化してロールを付けたとしても、プローブが 2xx を返せるとは限りません。採用を検討する場合は、SKU/機能の制約や実際の挙動をテスト環境で必ず検証し、難しいようなら後述の「ヘルスプロキシ」方式に切り替えるのが堅実です。

ヘルスチェック専用コンテナーだけを匿名読み取りにする

静的 Web サイト機能を使いたくない、または web サブリソースの Private Endpoint を増やしたくない場合は、ヘルスチェック専用コンテナーだけ匿名読み取りを許可する妥協案が現実的です。

構成イメージ

  • コンテナー名:health
  • ファイル:healthz.txt(内容は “OK” など)
  • プローブ先:https://<ストレージ名>.blob.core.windows.net/health/healthz.txt

設定手順(Storage 側)

  1. ストレージ アカウント設定で 「Allow Blob public access」が組織ポリシー上許可されているか確認する(無効だとコンテナー公開ができません)
  2. health コンテナーを作成し、パブリック アクセス レベルを Blob(推奨)に設定する
  3. healthz.txt をアップロードする

ここでの「匿名」は ネットワーク的に閉じた範囲でのみ成立させるのが肝です。Public network access を無効にし、Private Endpoint のみで到達させるなら、インターネットから “誰でも読める” 状態にはなりにくくなります。

Application Gateway 側のプローブ設定

Host は <ストレージ名>.blob.core.windows.net、Path は /health/healthz.txt とし、200 を許容する形にします。Host ヘッダー上書きの考え方は静的 Web サイトと同様です。

SAS をカスタム プローブに付与する(要件が許す場合)

「匿名アクセスは避けたいが、2xx を返す URL を用意したい」という場合、SAS を使ったヘルスチェックは合理的です。ただし、今回の前提では “SAS 無効/禁止” になっているため、採用するには要件整理が必要です。

設定の考え方

  • 権限は最小化(例:特定の1ファイルへの Read のみ)
  • 期限は短くし、ローテーションを前提にする(「長期限 SAS を固定で貼る」は避ける)
  • プローブ設定に秘密情報(SAS)を入れるなら、設定ファイルや IaC の扱いを厳格にする

プローブの指定例

多くのケースでは、SAS は Authorization ヘッダーよりも クエリ文字列として URL に付与する方が扱いやすいです。

Path: /health/healthz.txt?sv=...&sr=b&sig=...

別案として、Authorization: SharedAccessSignature ... のようにヘッダーで渡す構成が紹介されることもありますが、いずれにせよ “固定値の秘密” を AppGW 設定に持ち込む点は同じです。漏えいリスクとローテーションを設計に含めてください。

完全に閉域を維持したいなら「ヘルスプロキシ」を置く

「匿名も SAS も絶対に使えない」「それでもプローブで 200 を返したい」という要求は、Application Gateway 単体ではかなり厳しくなります。現実解としては、プローブ用の中継(ヘルスプロキシ)を用意して、そこから Storage を認証付きで確認させます。

アーキテクチャ例

Application Gateway (probe: /health) ──> Health Proxy (200/500 を返す)
                                           └─(Managed Identity / RBAC)─> Storage (Blob)

ヘルスプロキシは、例えば次のような実装が取りやすいです。

  • Azure Functions(HTTP トリガー)で、特定 Blob に HEAD(または SDK の GetProperties)で確認し、結果に応じて 200/500 を返す
  • Container Apps / AKS に軽量な API を置き、Storage SDK で疎通チェックして返す

この方式の利点は、Storage 側を「Private Endpoint のみ」「匿名/SAS 無し」のまま維持しつつ、Application Gateway のプローブ要件(2xx)も満たせる点です。追加コンポーネントは増えますが、セキュリティ要件が厳しいほどトータルの説明がしやすい構成になります。

よくあるハマりどころと対処

最後に、現場で頻出する詰まりポイントをまとめます。

症状原因のあたり対処の方向性
Backend health が Unhealthy、応答が見えないDNS が public に向いている/VNet リンク不足Private DNS ゾーンのリンク、DNS フォワーディング、VNet の DNS 設定を見直す
400 が返るHost ヘッダーが Storage と不一致HTTP settings でホスト名上書きを設定し、Storage の FQDN を送る
403/409 が返る認証不足(匿名不可のまま)静的 Web サイト/専用コンテナーの匿名化/SAS/ヘルスプロキシのいずれかに切り替える
HTTPS のみ失敗するSNI/証明書名の不一致、バックエンドを IP 指定しているホスト名上書き + SNI、または FQDN 指定に変更する

ログで確認すると早いポイント

  • Application Gateway の バックエンド正常性(Portal)で、失敗理由やステータスを確認する
  • 必要に応じて Application Gateway の アクセス ログ/パフォーマンス ログを Log Analytics に出して追う
  • Storage 側は 診断設定(Blob のログ)で、プローブが到達しているか・どのステータスを返しているかを見る

まとめ:セキュリティ要件と運用負荷で「落としどころ」を決める

Application Gateway のヘルス プローブで 2xx を返したい場合、最終的には「2xx を返すエンドポイントをどう用意するか」の設計になります。

  • 最短で安定:静的 Web サイト($web)にヘルスページを置く
  • 匿名範囲を絞る:ヘルスチェック専用コンテナーだけ匿名読み取りにする
  • 匿名は不可だが要件は緩められる:SAS で Read 最小権限・短期限・ローテーション
  • 匿名も SAS も絶対不可:ヘルスプロキシを用意して認証付きで確認する

「完全閉域 + 認証付きヘルスチェック」は、構成が複雑になりやすい一方で、監査や説明責任の観点では強い選択肢です。逆に、閉域(Private Endpoint + Public network access 無効)を前提にできるなら、ヘルスチェック用の最小限の匿名公開は、運用を大きく楽にしてくれます。自社ポリシーと運用体制に合わせて、無理のないパターンを選んでください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次