閉域環境で AWS から Azure OpenAI に接続するための構成と手順
この記事は、ナウキャスト Advent Calendar 2025 の7日目の記事です。
はじめに
エンタープライズ向け生成AIアプリケーション開発において、AWSを基盤としながらAI機能はAzure OpenAIを利用するといったマルチクラウド構成が増えています。特に金融系などセキュリティ要件の厳しい業界では、インターネットを経由しない閉域接続が求められるケースが多くあります。
本記事では、AWS上のアプリケーション(ECS)からAzure OpenAI Serviceへプライベート接続するための構成と構築手順を紹介します。
1. システム構成
AWS上のアプリケーションからAzure OpenAI Serviceへの通信は、Route 53 ResolverがDNSクエリをAzure DNS Private Resolverへ転送してプライベートIPを解決し、その後HTTPS通信を行う構成です。
以下の図は、DNS名前解決からAPI通信までの一連の流れを示しています。

具体的な通信フローは以下の通りです。
① DNS名前解決の要求(AWS側): ECS上のアプリケーションがOpenAIエンドポイント(<openai-resource-name>.openai.azure.com)の名前解決を要求します。
② DNSクエリの転送(AWS側): Route 53 ResolverのOutbound Endpointが、openai.azure.com ドメインに対するDNSクエリをAzure DNS Private ResolverのInbound Endpointへ転送します。
③ DNS名前解決(Azure側): Azure DNS Private Resolverがリクエストを受け取り、Azure内のPrivate DNS Zoneを参照します。Private DNS ZoneがOpenAIリソースに紐づいたAレコード(プライベートIPアドレス)をECS上のアプリケーションに返却します。
④ HTTPS通信の開始: 解決されたプライベートIPアドレスに対して、ECS上のアプリケーションからHTTPSリクエストが送信されます。
構成要素の説明
フロー図に登場する各構成要素の役割を以下にまとめます。
| 構成要素 | 配置場所 | 役割 |
|---|---|---|
| ECS | AWS VPC(Private Subnet) | クライアントアプリケーションが稼働。OpenAI APIへのリクエストを送信。 |
| Route 53 Resolver | AWS VPC |
openai.azure.com ドメインに対するDNSクエリをOutbound Endpointに送るルールを管理。 |
| Outbound Endpoint | AWS VPC(Private Subnet) | DNSクエリがAzure側へ転送される出口(ENI)。 |
| Azure DNS Private Resolver | Azure VNet(japaneast) | Inbound Endpointで受信したDNSクエリをPrivate DNS Zoneへ中継し、名前解決を実行。 |
| Inbound Endpoint | Azure VNet(japaneast) DNS Resolver用サブネット |
AWSからのDNSクエリを受け取る入口(NIC)。 |
| Private DNS Zone | Azure(Global) ※VNetにリンク |
OpenAIエンドポイントとプライベートIPの対応関係を管理。 |
| Private Endpoint | Azure VNet(japaneast) OpenAI用サブネット |
OpenAIリソースへの入り口としてVNet内に配置。 |
| Azure OpenAI Resource | Azure(eastus2) | OpenAIリソース本体。Private Endpoint経由でアクセス。 |
2. 設計時に考慮した事項
①サブネット分割
DNS Private Resolverの受信エンドポイント(Inbound Endpoint)には専用のサブネットが必要です。他のリソースと同じサブネットに作成することはできません。
参考: Azure DNS Private Resolver エンドポイントとルールセット
本構成においては以下2つのサブネットが必要になります。
-
OpenAI用サブネット
- Private Endpoint (PE) の配置
-
DNS Resolver用サブネット
- Azure DNS Private Resolver (Inbound Endpoint) の配置
サブネットサイズについて:
-
OpenAI用サブネット
- サブネット空間の最小は
/29ですが、今回は拡張性を考慮して/27としました。将来、複数のリソースへのPrivate Endpointを配置する可能性を考慮し、ある程度のサイズを確保しておくことを推奨します。
参考: サブネット空間の最小と最大制限
- サブネット空間の最小は
-
DNS Resolver用サブネット
- Azure DNS Private Resolverのサブネット制限により、
/28以上/24以下が必須になっています。
参考: Azure DNS Private Resolver のサブネット制限
- Azure DNS Private Resolverのサブネット制限により、
②Azure OpenAIのリージョン選択
今回、Azure OpenAIのリソースは「japaneast」ではなく「eastus2」に作成しました。日本からのアクセスであっても、Azure OpenAIに関しては最新モデルの提供スピードの面で、eastus2の方が有利なケースが多いためです。
参考: モデルの提供状況
物理的な距離によるレイテンシは発生しますが、生成AIの処理時間自体が長いため、許容範囲内であることがほとんどです。japaneastからeastus2へのレイテンシは、Azureネットワークレイテンシ表によると中央値(P50)で約164msと試算されます。
3. 構築手順詳細
実際の構築手順を解説します。本記事では、TerraformなどのIaCツールは使用せず、Azure PortalおよびAWS Management Consoleから手動で構築する手順を説明します。
Step 1: サブネットの準備 (Azure)
前述の設計に基づき、VNet内に2つのサブネットを作成します。
- OpenAI用サブネット
- DNS Resolver用サブネット
Step 2: NSGの設定 (Azure)
セキュリティグループを作成し、各サブネットに関連付けます。
AWSからの通信を許可するために以下のインバウンドルールが必要です。
| 用途 | プロトコル | ポート | 送信元IP | 必須適用先サブネット |
|---|---|---|---|---|
| DNS用 | Any (UDP/TCP) | 53 | AWS側のVPC CIDR | DNS Resolver用サブネット |
| HTTPS用 | TCP | 443 | AWS側のVPC CIDR | OpenAI用サブネット |
Step 3: OpenAIリソースとPrivate Endpointの作成 (Azure)
OpenAIリソースを作成し、Private Endpointを設定して、専用線経由のアクセスのみを受け入れる構成にします。
-
OpenAIリソースの作成とモデルデプロイ: Azure OpenAIリソースを作成し、Foundry Portalで必要なモデルをデプロイします。
-
パブリックアクセスの無効化: インターネット経由のアクセスを遮断し、プライベート接続のみを許可します。
- リソースのネットワーク設定でパブリックアクセスを「無効」に設定して保存します。
-
Private Endpointの作成: Azure VNet内にPrivate Endpointを作成し、OpenAIリソースへのプライベート接続の入口を用意します。DNS統合により、プライベートDNSゾーンが自動で作成され、ドメイン名とプライベートIPの対応が設定されます。
- Private Endpointを作成し、接続先のサブネットとして、OpenAI用サブネットを指定します。
- プライベートDNSゾーンと統合する設定をオンにすることで、
privatelink.openai.azure.comのDNSゾーンが自動的に作成され、Aレコード登録が自動化されます。
-
接続状態の確認: Private Endpointの接続状態が「承認済み」になっており、正常に接続されていることを確認します。
Step 4: DNS Private Resolverの作成 (Azure)
DNS Private Resolverを作成し、Inbound Endpointを設定して、AWS側からのDNSクエリを受け取れるようにします。
-
DNS Private Resolverの作成: DNS Private Resolverリソースを作成します。
-
Inbound Endpointの設定: Inbound Endpointを追加し、DNS Resolver用サブネットに配置します。
-
IPアドレスの記録: Inbound Endpointに割り当てられたプライベートIPアドレスはAWS側のRoute 53 resolverの設定でDNSクエリの宛先として登録するため、メモしておきます。
Step 5: Route 53 Resolverの設定 (AWS)
最後にAWS側の設定を行います。
-
セキュリティグループの作成: セキュリティグループを作成し、OutboundルールでTCP 53とUDP 53を、Azure DNS Private ResolverのInbound Endpoint IPアドレス(Step 4で取得したIPアドレス)に対して許可します。
-
Outbound Endpointの作成: Outbound Endpointを作成し、AWS VPC内のサブネットに関連付けます。作成したセキュリティグループを関連付けます。
-
Forwarding Ruleの作成:
openai.azure.comドメインに対するDNSクエリをAzure DNS Private Resolverへ転送するための転送ルールを作成します。- ルールタイプ: Forward (転送)
-
ドメイン名:
openai.azure.com- アプリが
<openai-resource-name>.openai.azure.comを呼び出す際のDNSクエリをAzure側へ転送するため、このドメインを指定します。
- アプリが
- Outbound Endpoint: 2で作成したOutbound Endpointを選択します。
-
ターゲットIPアドレス:
- Azure DNS Private Resolver の Inbound Endpoint IPアドレスを指定します(Step 4で取得したIPアドレス)。
-
VPCへの関連付け:
- アプリケーション(ECS)が存在するVPCに関連付けます。
これにより、AWS上のアプリケーションが <openai-resource-name>.openai.azure.comを名前解決する際、Route 53 Resolver が Azure DNS Private Resolver へ問い合わせを行い、プライベートIPが返却されるようになります。
4. 疎通確認
まずはAzure内部で疎通確認を行い、その後AWS側とAzure間の疎通確認を行います。
疎通確認を短縮する場合は、AWS側からのAPI呼び出しテストが成功すれば、動作確認可能です。API呼び出しが失敗した場合は、原因究明のために各経路を段階的に確認してください。
1. Azure内部からの疎通確認
Azure内部の同一VNet内のVMやコンテナから確認することで、Azure側の設定が正しく動作しているかを検証できます。
確認する項目:
| Step | 確認項目 | 詳細 |
|---|---|---|
| 1 | DNS名前解決 | ・Private DNS Zone → Private EndpointのIP解決(Port 53) |
| 2 | HTTPS通信 | ・Azure VNet内からPrivate EndpointへのHTTPS通信(Port 443) |
| 3 | APIリクエスト | ・Azure VNet内からPrivate Endpoint経由でAzure OpenAI ResourceへのAPIリクエスト(モデル呼び出し) |
Step 1: DNS名前解決
Private DNS Zoneが正しくPrivate EndpointのIPを返すかを確認します。
Resolve-DnsName -Name <openai-resource-name>.openai.azure.com
実行結果例
Name Type TTL Section NameHost
---- ---- --- ------- --------
<openai-resource-name>.openai.azure.com CNAME 900 Answer <openai-resource-name>.privatelink.openai.azure.com
Name : <openai-resource-name>.privatelink.openai.azure.com
QueryType : A
TTL : 10
Section : Answer
IP4Address : x.x.x.x # Azure Private EndpointのプライベートIPアドレス
Step 2: HTTPS通信
DNS解決が成功したら、次はTCP接続を確認します。
Test-NetConnection -ComputerName <openai-resource-name>.openai.azure.com -Port 443
実行結果例
ComputerName : <openai-resource-name>.openai.azure.com
RemoteAddress : x.x.x.x # Azure Private EndpointのプライベートIPアドレス
RemotePort : 443
InterfaceAlias : Ethernet
SourceAddress : x.x.x.x # 接続元のプライベートIPアドレス
TcpTestSucceeded : True
Step 3: APIリクエスト
OpenAIのAPIを呼び出し、モデルが正しくデプロイされているかを確認します。
# 環境変数のセット
$env:AZURE_OPENAI_ENDPOINT = "https://<openai-resource-name>.openai.azure.com/"
$env:AZURE_OPENAI_KEY = "<your-api-key>"
# リクエストボディの作成
$json = @{
messages = @(
@{
role = "user"
content = "Hello, world!"
}
)
max_completion_tokens = 100
model = "<deployment-name>"
} | ConvertTo-Json -Depth 3
# API呼び出し
Invoke-RestMethod -Uri "$env:AZURE_OPENAI_ENDPOINT/openai/deployments/<deployment-name>/chat/completions?api-version=2025-01-01-preview" `
-Method POST `
-Headers @{ "api-key" = $env:AZURE_OPENAI_KEY; "Content-Type" = "application/json" } `
-Body $json `
| ConvertTo-Json -Depth 10
実行結果例
{
"id": "chatcmpl-xxxxx",
"object": "chat.completion",
"created": 1749640256,
"model": "<model-name>",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 8,
"total_tokens": 18
}
}
2. AWS側からの疎通確認
Azure内部での確認が成功したら、次はAWS側からの確認を行います。
アプリケーションが稼働するECSタスクと同じネットワーク条件で検証するため、同一のプライベートサブネットに検証用EC2インスタンスを作成し、Session Managerで接続して確認しています。
確認する項目:
| Step | 確認項目 | 詳細 |
|---|---|---|
| 1 | DNS名前解決 | ・AWS VPC内からRoute 53 ResolverへのDNSクエリ ・Route 53 ResolverからAzure DNS Private ResolverへのDNS転送(Port 53) |
| 2 | HTTPS通信 | ・AWS側からAzure Private EndpointへのHTTPS通信(Port 443) |
| 3 | APIリクエスト | ・AWS側からPrivate Endpoint経由でAzure OpenAI ResourceへのAPIリクエスト(モデル呼び出し) |
Step 1: DNS名前解決
AWSのRoute 53 Resolverが正しくAzureへ転送していれば、Azure OpenAIのパブリックドメイン(openai.azure.com)を問い合わせた際に、CNAMEを経てプライベートIPアドレスが返ってきます。
dig +short <openai-resource-name>.openai.azure.com
実行結果例
<openai-resource-name>.privatelink.openai.azure.com.
x.x.x.x # Azure Private EndpointのプライベートIPアドレス
Step 2: HTTPS通信
DNS解決でプライベートIPが返ることを確認したら、そのIPの443ポートへ接続できるかを確認します。
nc -vz <openai-resource-name>.openai.azure.com 443
実行結果例
Ncat: Connected to x.x.x.x:443. # x.x.x.xはAzure Private EndpointのプライベートIPアドレス
Step 3: APIリクエスト
最後に、OpenAIのAPIを呼び出せるかを確認します。
# 環境変数のセット
export AZURE_OPENAI_ENDPOINT="https://<openai-resource-name>.openai.azure.com/"
export AZURE_OPENAI_KEY="<your-api-key>"
# リクエストボディの作成
cat > request.json <<EOF
{
"messages": [
{
"role": "user",
"content": "Hello, world!"
}
],
"max_completion_tokens": 100,
"model": "<deployment-name>"
}
EOF
# API呼び出し
curl -s -X POST \
"$AZURE_OPENAI_ENDPOINT/openai/deployments/<deployment-name>/chat/completions?api-version=2025-01-01-preview" \
-H "api-key: $AZURE_OPENAI_KEY" \
-H "Content-Type: application/json" \
-d @request.json \
| jq .
実行結果例
{
"id": "chatcmpl-xxxxx",
"object": "chat.completion",
"created": 1749640256,
"model": "<model-name>",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 8,
"total_tokens": 18
}
}
まとめ
今回はAWSからAzure OpenAI Serviceへ閉域接続するための構成と構築手順を紹介しました。
マルチクラウド間のDNS名前解決については、AWS Route 53 ResolverとAzure DNS Private Resolverを組み合わせることで実現していますが、これはAzure OpenAIに限らず他のサービスへの閉域接続時も応用可能です。
セキュリティ要件の厳しい企業環境で生成AIを活用する際に、本記事が参考になれば嬉しいです!
Discussion
勉強になりました✨