Azure OpenAI・AI Searchを閉域で使う|Private Endpointと仮想ネットワークの設計

プライベートエンドポイントを作っただけでは、通信は閉じません。

閉域化は「受信を閉じる」「送信を絞る」「名前解決を向け直す」の3つがそろって、はじめて成立します。

生成AIやAI-OCRを業務で使うとき、「データが社外に出ないようにしたい」というご要望をいただきます。Azureでこれに応える手段がプライベートエンドポイントとプライベートリンクですが、Microsoft Learn の各ページはサービスごとの手順書になっており、複数のサービスを組み合わせて1つの業務システムを閉域で組み上げるときの全体像は、読み手が自分で組み立てる必要があります。この記事では、その全体像と、設計時に判断が要る点を整理します。

株式会社ロクシアシステムズは、福岡と東京を拠点に、全国のお客様へ Microsoft 365・Azure の導入支援と、AIの業務活用(AIプライベート)の支援を提供しているIT企業です。また、お客様専用のセキュアなAI基盤SaaSサービス「AIプライベート」シリーズとして、帳票の読み取りと入力業務を自動化する「AI-OCRプライベート」も提供しています。

閉域にする目的をはっきりさせる

設計に入る前に、何のために閉じるのかを決めておきます。ここが曖昧なまま作り始めると、「とりあえず全部閉じる」に流れ、運用できない構成ができあがります。

実務でよく挙がる目的は3つです。1つ目は通信経路の説明責任で、社内のデータがインターネットを経由しないことを、構成図と設定で示せるようにすること。2つ目は資格情報が漏れた場合の被害の限定で、鍵やトークンが流出しても、許可したネットワークの外からは使えない状態にすること。3つ目は監査や取引先要件への適合です。

逆に、閉域化は「誰がアクセスしてよいか」を解決しません。ネットワークを閉じても、そのネットワークの中にいる人・アプリは通れます。認証と権限の設計は別に必要で、両方そろって守りになります。この考え方はゼロトラストの「侵害を前提とする」と同じ方向です。閉じた環境を社外から使えるようにする側の設計は、Azure Front Door の背後のアプリを守るで扱っています。

閉域化は「受信」「送信」「名前解決」の3層で考える

Azureの閉域化でつまずく原因のほとんどは、この3つを混同することにあります。役割が違うので、別々に設計して、別々に確認します。

層やること使う機能できていないと起きること
受信外から直接叩けないようにするプライベートエンドポイント/ファイアウォール(既定を拒否)/アクセス制限鍵さえ知っていれば、どこからでも使えてしまう
送信アプリの出口を仮想ネットワークに通し、行き先を絞る仮想ネットワーク統合/ネットワークセキュリティグループ/ルートテーブル閉域の相手に届かない。あるいは、意図しない外部に出られる
名前解決FQDNをプライベートIPに向けるプライベートDNSゾーン/DNSの委任設定は正しいのに、公開IPに向かって接続が拒否される

「プライベートエンドポイントを作ったのにつながらない」という相談は、ほぼ例外なく名前解決の層が抜けています。逆に「閉じたはずなのに外から叩けてしまう」は受信の層です。どの層の話をしているのかを毎回はっきりさせると、切り分けが早くなります。

受信を閉じる:プライベートエンドポイントはサブリソース単位

プライベートエンドポイントは、Microsoft Learn の定義では「仮想ネットワークのプライベートIPアドレスを使用するネットワークインターフェイス」です。サブネットからプライベートIPが1つ払い出され、そのIPが対象サービスにマップされます。IPはエンドポイントのライフサイクル全体で変わりません。

設計時に効いてくる性質が4つあります。

1. 接続は一方向

接続を開始できるのはクライアント側だけです。サービス側から呼び返す経路は作られません。コールバックが要る構成は、別の仕組みで設計します。

2. サブリソース単位で必要

Learn には「Azure Storage の場合、たとえば、サブリソースのファイルとBLOBにアクセスするための個別のプライベートエンドポイントが必要になります」と明記されています。ストレージを Blob とキューとテーブルで使うなら、その分だけエンドポイントが要ります。設計の段階で本数を数えておくことが大事で、これは後述のコストにも直結します。

3. 作っただけではパブリックは閉じない

ここが最も誤解されます。Learn の表現は「プライベートエンドポイントからは、AzureサービスでプライベートアクセスできるIPアドレスが提供されますが、必ずしもパブリックネットワークアクセスを制限する必要はありません」です。つまりエンドポイントは経路を1本増やすだけで、従来の公開経路は開いたままです。受信を閉じるには、サービス側でパブリックネットワークアクセスを無効にするか、ファイアウォールの既定動作を拒否に変える操作が別に必要です。

4. 同じリージョン・同じサブスクリプション

エンドポイントは仮想ネットワークと同じリージョン・同じサブスクリプションに置きます。接続先のサービス自体は別リージョンでも構いません。

要点

プライベートエンドポイントは「入口を1本足す」機能です。「公開の入口を閉める」のは別の設定です。両方やって、はじめて受信が閉じます。

送信を絞る:仮想ネットワーク統合とネットワークセキュリティグループ

閉域に置いたデータベースやAIサービスへアプリから接続するには、アプリの送信を仮想ネットワークに通す必要があります。Azure Functions や App Service では仮想ネットワーク統合がこれにあたります。Learn は「仮想ネットワーク統合はアプリからのアウトバウンドトラフィックに影響を与えます。アプリへのプライベートなインバウンドアクセスは提供していません」と、受信とは別物であることをはっきり書いています。

統合サブネットには次の性質があります。プランによって条件が違うので、ここは公式の表を必ず確認してください。

項目Flex ConsumptionElastic Premium/専用(App Service)
サブネットの委任先Microsoft.App/environmentsMicrosoft.Web/serverFarms
最小サブネットサイズ/27/28
推奨サイズ/27(単一アプリ)、/26(複数アプリ)/24〜/26(OSとプランによる)
送信の既定すべて仮想ネットワーク経由(「すべてルーティング」の設定は不要)既定はインターネットへ出られる。「すべてルーティング」を有効にして強制する

とくに注意したいのが最終行です。Learn は「Flex Consumption の場合、すべてのトラフィックは仮想ネットワーク経由で既にルーティングされており、すべてルーティングは必要ありません」としています。つまりこのプランでは、統合した時点でアプリの出口はすべて仮想ネットワークを通り、統合サブネットに付けたネットワークセキュリティグループの送信規則が、外部への通信すべてに効きます。

ここで「Internet 宛を既定で拒否し、必要な行き先だけを開ける」という設計を採ると、閉域としては筋が通ります。サービスタグを使えば、Microsoft Entra・リージョンのAzureサービス・Azure Monitor・Azure Resource Manager といった単位で開けられます。ただし開け忘れた行き先はすべて無言で落ちます。後述しますが、アプリから外部のWebhookへ通知を飛ばす、といった処理はここで止まります。

なお、統合サブネットに置いたネットワークセキュリティグループの受信規則はアプリに適用されません。アプリへの受信を制御するのはアクセス制限機能です。またリージョン仮想ネットワーク統合ではポート25が使えません。

Azure CLI — 統合サブネットの委任先を確認する
az network vnet subnet show \
  --resource-group <リソースグループ> \
  --vnet-name <仮想ネットワーク名> \
  --name <サブネット名> \
  --query "delegations[].serviceName" -o tsv

もうひとつ、統合サブネットは使い回せません。プライベートエンドポイントやサービスエンドポイントに使っているサブネット、別のホスティングプランに委任済みのサブネットは選べません。Flex Consumption の統合サブネットと Container Apps 環境のサブネットを共有することもできません。サブネットは割り当て後にサイズを変更できないため、最初の設計で余裕を持たせておきます。

名前解決を向け直す:プライベートDNSゾーン

プライベートエンドポイントを作ると、対象サービスの公開DNSに privatelink を含む別名へのCNAMEが作られます。仮想ネットワークの中では、この別名をプライベートIPに解決させる必要があり、その役目を担うのがプライベートDNSゾーンです。ゾーンを仮想ネットワークにリンクすることで、アプリ側の接続文字列を変えずに宛先だけが切り替わります。

ゾーン名はサービスごとに決まっています。AI基盤でよく使う組み合わせを抜粋します。

サービス(サブリソース)プライベートDNSゾーン名
Azure AI services/Azure OpenAI(account)privatelink.cognitiveservices.azure.com/privatelink.openai.azure.com/privatelink.services.ai.azure.com
ストレージ(blob)privatelink.blob.core.windows.net
ストレージ(queue/table/file)privatelink.queue.core.windows.net ほか、サブリソースごとに別ゾーン
Azure Cosmos DB(SQL)privatelink.documents.azure.com
Azure AI Searchprivatelink.search.windows.net
Azure Key Vaultprivatelink.vaultcore.azure.net
App Service/Functionsprivatelink.azurewebsites.net(SCM用のAレコードも同じゾーンに作る)

ここで踏みやすい罠を3つ挙げます。

ゾーンを複数サービスで共用しない

Learn は「1つのAzureサービスにリンクされている既存のプライベートDNSゾーンは、2つの異なるAzureサービスのプライベートエンドポイントに関連付けてはなりません。これにより、最初のAレコードが削除され、それぞれのプライベートエンドポイントからそのサービスにアクセスしようとすると解決の問題が発生します」と警告しています。サービスごとにゾーンを分けます。

AIサービスは3系統のエンドポイントを持ちうる

1つのリソースが cognitiveservices・openai・services.ai の3系統のエンドポイントを公開できます。Learn は「ワークロードが使用する各エンドポイントごとにDNSを設定してください」としています。使う系統のゾーンだけ作ってあると、別の系統を叩いたSDKがそこだけ失敗します。

ゾーンに無い名前は NXDOMAIN になる

プライベートDNSゾーンをリンクすると、そのゾーン配下の名前解決はゾーンが引き受けます。レコードが無い名前は「見つからない」として返るため、同じ種類の別リソース(プライベートエンドポイントを持たない公開リソース)に接続していた処理が巻き添えで落ちることがあります。必要ならインターネットへのフォールバックを設定します。

「名前が引けること」と「アクセスできること」は別物

閉域化したあと、社外のPCから privatelink の名前が引けてしまうことに気づいて、漏洩ではないかと不安になる方がいます。結論から言うと仕様どおりで、閉域は壊れていません。

Microsoft Learn の記述は明快です。「DNSの解決とアクセス制御は独立しています」とし、公開DNS側の privatelink のCNAMEチェーンは、ハイブリッド構成や段階的な移行のために、インターネット上のどこからでも意図的に解決できるようにしてあると説明しています。そのうえで、

「パブリックDNS参照が成功すると、その正確な名前を持つリソースがグローバルAzure名前空間に存在することのみが確認されます。プライベートエンドポイントがアタッチされていること、プライベートエンドポイントのIPを明らかにしていること、またはデータプレーンアクセスを許可するかどうかは確認されません。(中略)リソースの存在は列挙可能です。リソースへのアクセスは無効です」

と締めています。名前が引けることと、そこへ入れることは、Azureでは別々に制御されています。したがって「外から名前が引けるか」は閉域の確認方法として使えません。確認すべきは、仮想ネットワークの中から引いたときにプライベートIPが返ること、そして外からアクセスしたときに拒否されることの2点です。

確認の順番

  1. 仮想ネットワークの中から名前を引き、プライベートIPが返ることを見る
  2. そのIPへ実際に接続できることを見る
  3. 仮想ネットワークの外から接続し、拒否されることを見る

この3つがそろって、閉域が成立していると言えます。

AIサービスを閉域で使うときの固有の注意

Azure OpenAI や Document Intelligence などのAIサービス(Azure AI services)には、ストレージやデータベースとは違う作法があります。実装で必ず当たる3点を挙げます。

1. 既定動作を「拒否」にしないと、ネットワーク規則は効かない

Learn は同じページ内で2回、「拒否するように既定のルールを設定します。そうしないと、ネットワーク規則は効力を発揮しません」と強調しています。許可リストを丁寧に書いても、既定が許可のままなら素通りします。

Azure CLI — AIサービスの既定動作を拒否に変える
az cognitiveservices account show \
  --resource-group <リソースグループ> --name <アカウント名> \
  --query id --output tsv

az resource update --ids <上で得たリソースID> \
  --set properties.networkAcls.defaultAction=Deny

なお、ファイアウォールを有効にすると「他のAzureサービスからの要求、Azureポータルからの要求、ログおよびメトリックサービスからの要求」もブロック対象に含まれます。閉じた直後にポータルの画面が動かなくなるのは、この仕様によるものです。

2. カスタムサブドメインが必須

Learn は「仮想ネットワークから送信されたエンドポイント要求は、アカウントのカスタムサブドメインとして設定する必要があります」と書いています。リージョン共通のエンドポイントのままでは、閉域からの要求が通りません。カスタムサブドメイン名はテナントをまたいで一意なので、ありふれた名前は他社にすでに取られている可能性があります。似た名前を取り違えると、認証時に「トークンのテナントとリソースのテナントが一致しない」という、原因の分かりにくいエラーになります。命名規則を決めて、リソース名と一致させておくのが安全です。

3. privatelink のURLを直接呼ばない

Learn には警告として「Azure内部の中間CNAME解決の一部である内部URL *.privatelink.openai.azure.com を呼び出さないでください」とあります。呼ぶべきはあくまでカスタムサブドメインのURLで、privatelink 側は名前解決の途中経過です。動作確認のときに直接叩いてしまい、そのままコードに残るという事故が起こりやすい箇所です。

また、Azure OpenAI には「信頼されたAzureサービス」の例外があり、networkAcls.bypass を AzureServices にすると、Azure AI services・Azure Machine Learning・Azure AI Search がマネージドIDで到達できるようになります。AI Search から OpenAI を呼ぶ構成では、これを使うか、素直にプライベートエンドポイントを増やすかの判断が要ります。

閉じると動かなくなるもの、と切り分けの道具

閉域化でいちばん見落とされるのが、閉じたことの副作用です。設計の時点で洗い出しておくと、運用開始後の障害対応が減ります。

動かなくなるもの対処の方向
外部サービスへの通知(チャットツールのWebhookなど)送信が仮想ネットワーク経由になり、外向きを絞ると止まる。監視・通知はプラットフォーム側の仕組みに寄せるのが素直
ポータルの「テスト」画面関数アプリにCORSオリジンを追加し、アクセス制限にサービスタグ AzureCloud を許可する
手元からのデプロイ仮想ネットワークの中から実行するか、作業時だけ送信元IPを一時的に許可して、終わったら戻す
ログ・メトリックの収集AIサービスのファイアウォールはこれもブロック対象。必要な経路を明示的に開ける
公開リソースへの名前解決プライベートDNSゾーンの守備範囲に入った名前は、レコードが無いと解決できない

切り分けの道具も押さえておきます。Kudu コンソールでは、セキュリティ上の制約から、一般的な疎通確認のコマンド(ICMPでの応答確認・DNS参照・経路追跡)が動きません。代わりに nameresolver と tcpping が用意されています。名前解決の失敗とTCP到達性の失敗を分けて見られるので、先ほどの3層のどこで詰まっているかがすぐに分かります。

Kudu コンソール — 名前解決とTCP到達性を分けて確かめる
nameresolver <カスタムサブドメイン>.openai.azure.com
tcpping <カスタムサブドメイン>.openai.azure.com 443

目安として、DNSのタイムアウトはDNSサーバーごとに3秒、経路がふさがれている場合のTCPタイムアウトは21秒です。「3秒で落ちるなら名前解決、20秒以上待たされるなら経路」と当たりを付けられます。

最後に運用面を2つ。1つは仮想ネットワーク統合を切断せずにアプリやプランを削除しないことです。サブネットに委任が残り、その仮想ネットワークやサブネットの更新・削除ができなくなります。復旧には同じ名前でアプリを作り直し、統合してから切断する、という手間がかかります。もう1つはコストで、プライベートエンドポイントは本数に応じた課金です。サブリソース単位で必要になるため本数が増えやすく、小規模な構成ではインフラ費用の大きな割合をここが占めることがあります。閉域の範囲は、守りたいものに合わせて決めるのが結局は経済的です。費用の考え方はAI-OCRの費用・料金もあわせてご覧ください。

弊社の支援

弊社は、お客様専用のAI基盤をAzure上に構築する形でAIの業務活用を支援しています。閉域化については、「どこまで閉じるか」をご要件から決めるところからご一緒します。全部を閉じることが目的ではなく、守りたいデータと、説明が必要な相手に合わせて範囲を決めるほうが、費用も運用負荷も抑えられるためです。

構成はコードで管理し、検証用の環境を同じ形で用意して、本番に反映する前に確認できるようにしています。データの所在についての考え方はソブリンクラウドとはで、インフラをコードで払い出す運用はAzureのインフラ払い出しをセルフサービス化するで扱っています。

よくあるご質問

こちらをクリックして「よくある質問」を表示

プライベートエンドポイントを作れば、パブリックからのアクセスは自動的に塞がりますか?

塞がりません。プライベートエンドポイントは接続経路を1本追加する機能で、既存の公開経路はそのまま残ります。受信を閉じるには、対象サービス側でパブリックネットワークアクセスを無効にするか、ファイアウォールの既定動作を拒否へ変更する操作が別に必要です。

社外から privatelink の名前が引けてしまいます。設定を間違えていますか?

間違いではありません。Microsoft Learn は「DNSの解決とアクセス制御は独立しています」とし、名前が引けても、プライベートエンドポイントのIPが明かされるわけでも、アクセスが許可されるわけでもないと明記しています。閉域の確認は、仮想ネットワークの中からプライベートIPが返ること、外からのアクセスが拒否されることの2点で行ってください。

1つのプライベートDNSゾーンを複数のサービスで使い回せますか?

使い回さないでください。Microsoft Learn は、1つのサービスにリンク済みのゾーンを別のサービスのプライベートエンドポイントに関連付けると、最初のAレコードが削除され、名前解決の問題が発生すると警告しています。サービスごとにゾーンを分けて作成します。

閉域にすると、開発や保守がやりにくくなりませんか?

経路を設計しておけば運用できます。ポータルからのテストにはCORSオリジンの追加とサービスタグの許可、デプロイには仮想ネットワーク内からの実行や作業時だけの一時許可といった手段があります。大事なのは、こうした作業経路を設計段階で決めて手順にしておくことで、運用開始後に場当たりで穴を開けると閉域の意味が薄れます。

統合用のサブネットは、既存のものを使い回せますか?

使い回せません。プライベートエンドポイントやサービスエンドポイントに使用中のサブネット、他のホスティングプランへ委任済みのサブネットは選択できません。委任先もプランによって異なります。サブネットは割り当て後にサイズを変更できないため、将来のスケールを見込んだサイズで確保してください。

閉域化すれば、アクセス権限の設計は不要になりますか?

不要にはなりません。ネットワークを閉じても、そのネットワークの中にいる利用者やアプリケーションは到達できます。誰が何をしてよいかは認証と権限で制御する必要があり、ネットワークの閉域化と組み合わせてはじめて守りになります。

お客様専用のAI基盤をAzure上にどう構築するか、閉域の範囲をどこまでにするかは、ご要件によって変わります。現在の環境やご要望をお聞かせいただければ、構成案と進め方をご提案します。お問い合わせよりお気軽にご相談ください。

関連サービス・関連コラム

まずは無料トライアルで、効果をご確認ください

「AIプライベート」は短期・低コストで試せます。帳票入力(AI-OCR)・電話対応(AI-Voice)・計画づくり(AI-Enhance)の自動化から、クラウド(Azure・Microsoft 365)・DXのご相談まで、お気軽にどうぞ。