🔒

閉域環境で AWS から Azure OpenAI に接続するための構成と手順

に公開1

この記事は、ナウキャスト 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通信までの一連の流れを示しています。

Azure OpenAI接続フロー

具体的な通信フローは以下の通りです。

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つのサブネットが必要になります。

  1. OpenAI用サブネット

    • Private Endpoint (PE) の配置
  2. DNS Resolver用サブネット

    • Azure DNS Private Resolver (Inbound Endpoint) の配置

サブネットサイズについて:

  • OpenAI用サブネット

    • サブネット空間の最小は/29ですが、今回は拡張性を考慮して /27 としました。将来、複数のリソースへのPrivate Endpointを配置する可能性を考慮し、ある程度のサイズを確保しておくことを推奨します。
      参考: サブネット空間の最小と最大制限
  • DNS 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を設定して、専用線経由のアクセスのみを受け入れる構成にします。

  1. OpenAIリソースの作成とモデルデプロイ: Azure OpenAIリソースを作成し、Foundry Portalで必要なモデルをデプロイします。

  2. パブリックアクセスの無効化: インターネット経由のアクセスを遮断し、プライベート接続のみを許可します。

    • リソースのネットワーク設定でパブリックアクセスを「無効」に設定して保存します。
  3. Private Endpointの作成: Azure VNet内にPrivate Endpointを作成し、OpenAIリソースへのプライベート接続の入口を用意します。DNS統合により、プライベートDNSゾーンが自動で作成され、ドメイン名とプライベートIPの対応が設定されます。

    • Private Endpointを作成し、接続先のサブネットとして、OpenAI用サブネットを指定します。
    • プライベートDNSゾーンと統合する設定をオンにすることで、 privatelink.openai.azure.com のDNSゾーンが自動的に作成され、Aレコード登録が自動化されます。
  4. 接続状態の確認: Private Endpointの接続状態が「承認済み」になっており、正常に接続されていることを確認します。

Step 4: DNS Private Resolverの作成 (Azure)

DNS Private Resolverを作成し、Inbound Endpointを設定して、AWS側からのDNSクエリを受け取れるようにします。

  1. DNS Private Resolverの作成: DNS Private Resolverリソースを作成します。

  2. Inbound Endpointの設定: Inbound Endpointを追加し、DNS Resolver用サブネットに配置します。

  3. IPアドレスの記録: Inbound Endpointに割り当てられたプライベートIPアドレスはAWS側のRoute 53 resolverの設定でDNSクエリの宛先として登録するため、メモしておきます。

Step 5: Route 53 Resolverの設定 (AWS)

最後にAWS側の設定を行います。

  1. セキュリティグループの作成: セキュリティグループを作成し、OutboundルールでTCP 53とUDP 53を、Azure DNS Private ResolverのInbound Endpoint IPアドレス(Step 4で取得したIPアドレス)に対して許可します。

  2. Outbound Endpointの作成: Outbound Endpointを作成し、AWS VPC内のサブネットに関連付けます。作成したセキュリティグループを関連付けます。

  3. 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を活用する際に、本記事が参考になれば嬉しいです!

Finatext Tech Blog

Discussion

anshuanshu

勉強になりました✨