Azure OpenAIを使ったチャットボットWebアプリをAzureに閉じたネットワーク環境に構築する方法

「インターネットを経由した通信をどうしても行わせたくない」という場合は、このような構成を実装すれば可能です。
2023.07.05

みなさん、こんにちは!
福岡オフィスの青柳です。

前回のブログ記事では、「Azure OpenAI Service」を使ったチャットボットWebアプリを「Microsoft Azure」環境上に構築する手順をご紹介しました。

ご紹介した環境は、比較的シンプルな構成で実現できるものの、もしかするとネットワーク的なセキュリティ面で不安に感じる方もいらっしゃるかもしれません。

と言うのも、利用しているAzureの各サービス「Azure Open AI Service」や「Azure App Service」は、デフォルトではインターネットを経由して利用するようになっています。 そのため、悪意のある人間がこれらのサービスに対して不正なアクセスを試みたり、通信内容の盗聴を試みることが考えられます。

もちろん、サービスに対する通信はTLSやHTTPSで暗号化されていますし、APIキーやIDプロバイダ (Azure AD等) による認証もあるため、直ちに危険ということはありません。

それでも、企業のセキュリティポリシーや国・業界団体の規制に準拠する必要性から「インターネットを経由した通信を行わせたくない」という要求は少なからずあるでしょう。

このような要求を満たすためには、以下を実装する必要があります。

  • Azure上にインターネットから隔離された仮想ネットワーク環境を構築する
  • 各サービスのエンドポイントに対するインターネット経由のアクセスを禁止し、Azure内部の仮想ネットワークからのアクセスのみを許可する
  • 企業のオンプレミス環境とAzureの仮想ネットワークを専用線またはVPNでセキュアに接続する

構成図で表してみると、以下のようになります。

前回のブログ記事で構築した環境に比べて、一気に複雑になりました。

ですが、心配しないでください。 全体をいくつかのパートに分けて、一つずつ解説していきますので、ご安心ください。

構築する環境の構成

改めて、今回構築する環境の構成を以下に示します。

最初に提示した構成図では、左端の「オンプレミス環境」とAzureを接続する「ExpressRoute (Azureの専用線接続サービス)」や「Site-to-Site VPN」を構築するのが大変です。

そこで、今回はオンプレミス環境に見立てたテスト環境をAzure上の仮想ネットワーク (VNet) として構築して、インターネットを経由せずにAzure OpenAI Serviceを使ったチャットボットを利用する環境を構築することを目指します。

なお、今回の環境のベースとなる「Azure OpenAI Service」と「App Service」のシンプルな構成は、前回のブログ記事で構築した環境をそのまま使います。 まだ環境を構築していないという方は、前回のブログ記事を参照してください。

Azure OpenAIを使ったチャットボットWebアプリをAzure App Serviceでホストしてみた | DevelopersIO

環境構築 (その1:App ServiceからAzure OpenAI Serviceへの接続をAzure内で完結させる)

構成図の右側から順に構築して行きます。

まずは、「App Service」から「Azure OpenAI Service」に対する通信をAzure内で完結させるため、以下の手順を行います。

  • (1) バックエンドの「仮想ネットワーク (VNet)」を作成する
  • (2) 「Azure OpenAI Service」に対するアクセス元を制限する
  • (3) 「Azure OpenAI Service」向けの「プライベートエンドポイント」を作成する
  • (4) 「プライベートDNSゾーン (privatelink.openai.azure.com)」をVNetへリンクする
  • (5) 「App Service」の「VNet統合」を設定する

(1) バックエンドの「仮想ネットワーク (VNet)」を作成する

Azureポータル画面で「すべてのサービス」を開き、カテゴリ「ネットワーキング」にある「仮想ネットワーク」をクリックします。

仮想ネットワーク (VNet) の画面が開きますので、上部メニューにある「作成」をクリックします。

ウィザード画面に沿って必要な情報を入力して行きます。

項目名 設定値
プロジェクトの詳細 サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
インスタンスの詳細 仮想ネットワーク名 任意の名前を指定 (例:kumamon-vnet-backend)
地域 (Asia Pacific) Japan East

続いて、セキュリティに関する設定項目を入力します。

項目名 設定値
Azure Bastion Azure Bastionを有効にする チェックを入れない
Azure Firewall Azure Firewallを有効にする チェックを入れない
Azure DDoSネットワーク保護 Azure DDoS Network Protectionを有効にする チェックを入れない

今回は全てデフォルトのままとします。

続いて、VNetとサブネットのIPアドレスについて入力します。

まずはVNetのIPアドレスを指定します。 IPアドレス範囲 (CIDR) は何でも構いませんが、今回は以下のように設定してみました。

項目名 設定値
開始アドレス 10.0.0.0
ネットワークサイズ /16

次に、デフォルトで登録されているサブネットを「削除」します。

「サブネットの追加」をクリックします。

1つ目のサブネットの情報を入力します。

項目名 設定値
サブネットの詳細 サブネットテンプレート Default (変更しない)
名前 AppSubnet
開始アドレス 10.0.0.0
サブネットサイズ /24

「セキュリティ」の各項目はデフォルトのままにします。

「OK」をクリックして設定を保存しましたら、再び「サブネットの追加」をクリックします。

1つ目と同様にして、2つ目のサブネットの情報を入力します。

項目名 設定値
サブネットの詳細 サブネットテンプレート Default (変更しない)
名前 OpenAISubnet
開始アドレス 10.0.1.0
サブネットサイズ /24

以下のように2つのサブネットの情報が入力されていることを確認します。

設定内容を入力しましたら、「確認 + 作成」をクリックしてVNetおよびサブネットを作成します。

(2) 「Azure OpenAI Service」に対するアクセス元を制限する

Azure OpenAI Serviceに対してインターネット経由でのアクセスが行えないように設定します。

前回のブログ記事で作成した「Azure OpenAI Service」のリソース画面を開いて、左側のメニューから「ネットワーク」を選択します。 「Firewalls and virtual networks」タブが選択されていることを確認します。

「許可するアクセス元」の設定値を以下のように変更します。

項目名 設定値
許可するアクセス元 「全てのネットワーク」から「無効」に変更する

設定を変更しましたら、「Save」をクリックして保存します。 設定が反映されるまでしばらくかかるため、待ちます。

設定が反映されましたら、ここで一度、動作確認をしてみましょう。

前回のブログ記事で行ったように、WebブラウザでチャットボットのWebアプリへアクセスします。

上図のようにエラーが表示されましたか?

エラーが表示されればOKです。

チャットボットのWebアプリ (App Service) はAzure OpenAI ServiceのAPIに対してインターネット経由でアクセスしようとしますが、Azure OpenAI Service側でインターネット経由でのアクセスを拒否しているため、アクセスできないのが正解です。

もしエラーとならずに正常に表示されてしまう場合は、少し待ってから再度アクセスしてみてください。 それでも駄目なら、ここまでの設定手順を見直してみましょう。

(3) 「Azure OpenAI Service」向けの「プライベートエンドポイント」を作成する

Azure OpenAI Serviceに対してインターネット経由でのアクセスができないように設定しましたが、このままではAzure内部からのアクセスも行えません。

Azure内部からAzure OpenAI Serviceに対してアクセスできるようにするために、手順(1)で作成したVNetにAzure OpenAI Serviceの「プライベートエンドポイント」を作成します。 (「プライベートエンドポイント」は、厳密に言うと少し違うかもしれませんが、AWSで言うところの「VPCエンドポイント」のようなものです)

プライベートエンドポイントを作成する手順は何通りかありますが、今回は「Azure OpenAI Service」のリソース画面から作成する方法を採用します。

Azure OpenAI Serviceのリソース画面で、左側のメニューから「ネットワーク」を選択します。 「プライベートエンドポイント接続」タブを選択してから、「+プライベートエンドポイント」をクリックします。

ウィザード画面に沿って必要な情報を入力して行きます。

項目名 設定値
プロジェクトの詳細 サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
インスタンスの詳細 名前 任意の名前を指定 (例:kumamon-openai-endpoint)
ネットワークインターフェイス名 (「名前」欄を入力すると当項目も自動的に設定されます)
地域 Japan East

続いて、プライベートエンドポイントを作成する対象のリソースについて入力します。

項目名 設定値
サブスクリプション リソース作成先のサブスクリプション (変更不可)
リソースの種類 Microsoft.CognitiveServices/accounts (変更不可)
リソース Azure OpenAI Serviceのリソース名 (変更不可)
対象サブリソース account

「Azure OpenAI Service」の画面からプライベートエンドポイントを作成する場合、ほとんどの設定項目は既に指定された状態になっているため、改めて指定する必要はありません。

「対象サブリソース」のみ指定可能になっていますが、選択できる値は「account」しか表示されませんので、必然的にそちらを選ぶことになります。

続いて、プライベートエンドポイントを作成するVNetについて入力します。

項目名 設定値
ネットワーク 仮想ネットワーク 手順(1)で作成したバックエンドのVNetを選択
サブネット OpenAISubnet
プライベートエンドポイントのネットワークポリシー 無効
プライベートIP構成 IPアドレスを動的に割り当てる
アプリケーションセキュリティグループ (設定しない)

バックエンドのVNetを作成する際に「AppService」「OpenAIService」という2つのサブネットを作成しましたね。 これらのうち「OpenAISubnet」をプライベートエンドポイントの作成先に指定します。

続いて、「プライベートDNSゾーン」と呼ばれるAzure内部で使われるDNSに関する設定項目を入力します。

項目名 設定値
プライベートDNSゾーンと統合する はい
プライベートDNSゾーン 構成名 privatelink-openai-azure-com
サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
プライベートDNSゾーン privatelink.openai.azure.com

プライベートエンドポイントを「プライベートDNSゾーン」と統合することにより、VNetからプライベートエンドポイント経由でリソースへアクセスする際に、Azure内部のDNSを使った名前解決が行えるようになります。

続いて、「タグ」の設定ページに遷移して、必要に応じてタグの設定を行った後、最後に「確認および作成」へ進んでプライベートエンドポイントの作成を完了します。

(4) 「プライベートDNSゾーン (privatelink.openai.azure.com)」をVNetへリンクする

前の手順で「プライベートエンドポイント」を作成した際、併せて「プライベートDNSゾーン」も作成されています。 このプライベートDNSゾーンを使って名前解決を行えるようにするために、プライベートDNSゾーンをバックエンドのVNetへリンクします。

Azureポータル画面を使ってここまでの手順通りに進めた場合、プライベートDNSゾーンが作成された時に自動的にVNetへのリンクも設定されるようです。 自動的に仮想ネットワークリンクが作成されている場合、この手順はスキップして構いません。 もし仮想ネットワークリンクが作成されていない場合は、この手順を行ってください。

「リソースグループ」画面に表示されているリソースの一覧からprivatelink.openai.azure.comという名前のプライベートDNSゾーンを選択します。

画面左側のメニューから「仮想ネットワークリンク」を選択します。

以下の画面になりますので、「追加」をクリックします。

必要な情報を入力します。

項目名 設定値
リンク名 任意の名前を指定 (例:kumamon-vnet-backend-link)
仮想ネットワークのリソースIDを知っています チェックを入れない
サブスクリプション リソース作成先のサブスクリプションを選択
仮想ネットワーク 手順(1)で作成したバックエンドのVNetを選択
自動登録を有効にする チェックを入れない

「OK」をクリックして仮想ネットワークリンクの作成を完了します。

(5) 「App Service」の「VNet統合」を設定する

ここまでの手順で、バックエンドのVNetからAzure OpenAI Serviceに対してアクセスするための必要な設定は終わりました。

最後に、App ServiceからバックエンドVNetに対してアクセスできるように設定します。

前回のブログ記事で作成した「App Service」のリソース画面を開いて、左側のメニューから「ネットワーク」を選択します。

右の方にある「送信トラフィック」の中から「VNET統合」をクリックします。

以下の画面になりますので、「VNetの追加」をクリックします。

必要な情報を入力します。

項目名 設定値
サブスクリプション リソース作成先のサブスクリプションを選択
仮想ネットワーク 手順(1)で作成したバックエンドのVNetを選択
サブネットの指定方法 既存のものを選択
サブネット AppSubnet

バックエンドのVNetを作成する際に作成した2つのサブネットのうち、今度は「AppSubnet」の方を指定します。

「OK」をクリックしてVNet統合の設定を完了します。

ここまでの作業結果の確認

ここまでの手順によって、App Serviceからインターネット経由ではなくVNet経由でAzure OpenAI Serviceに対してアクセスできるようになりました。

実際にアクセスできるか確認しましょう。

手順(2)の時点で、WebブラウザでチャットボットのWebアプリへアクセスした際は、チャットボットのWebアプリからAzure OpenAI Serviceへアクセスできないためエラーが表示されました。

ここで再び、WebブラウザでチャットボットのWebアプリへアクセスしてみましょう。

どうでしょう? 今度は正常にチャットボットの画面が表示されましたか?

正常に表示されていれば、ここまでの手順は問題なく完了しています。

もし、正常に表示されない場合は、ここまでの手順をもう一度確認してみましょう。

環境構築 (その2:App Serviceへの接続をAzure内で完結させる)

今度は構成図の左側を構築して行きます。

「App Service」に対する通信をAzure内で完結させるため、以下の手順を行います。

  • (6) フロントエンドの「仮想ネットワーク (VNet)」を作成する
  • (7) 「App Service」に対するアクセス元を制限する
  • (8) 「App Service」向けの「プライベートエンドポイント」を作成する
  • (9) 「プライベートDNSゾーン (privatelink.azurewebsites.net)」をVNetへリンクする
  • (10) 「DNS Private Resolver」を作成する

(6) フロントエンドの「仮想ネットワーク (VNet)」を作成する

作成方法は、手順(1)で作成した「バックエンドの仮想ネットワーク (VNet)」と同じです。

「仮想ネットワーク」画面で「作成」をクリックして、ウィザード画面に沿って設定項目を入力して行きます。

項目名 設定値
プロジェクトの詳細 サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
インスタンスの詳細 仮想ネットワーク名 任意の名前を指定 (例:kumamon-vnet-frontend)
地域 (Asia Pacific) Japan East

セキュリティに関する設定項目は、全てデフォルトのままとします。(画面キャプチャは省略します)

項目名 設定値
Azure Bastion Azure Bastionを有効にする チェックを入れない
Azure Firewall Azure Firewallを有効にする チェックを入れない
Azure DDoSネットワーク保護 Azure DDoS Network Protectionを有効にする チェックを入れない

VNetとサブネットのIPアドレスについて入力します。

VNetのIPアドレス:

項目名 設定値
開始アドレス 10.1.0.0
ネットワークサイズ /16

サブネット (1つ目):

項目名 設定値
サブネットの詳細 サブネットテンプレート Default (変更しない)
名前 AppSubnet
開始アドレス 10.1.0.0
サブネットサイズ /24

サブネット (2つ目):

項目名 設定値
サブネットの詳細 サブネットテンプレート Default (変更しない)
名前 DNSResolverSubnet
開始アドレス 10.1.1.0
サブネットサイズ /24

設定内容を入力しましたら、「確認 + 作成」をクリックしてVNetおよびサブネットを作成します。

(7) 「App Service」に対するアクセス元を制限する

Azure OpenAI Serviceで設定したのと同様に、今度はApp Serviceに対してインターネット経由でのアクセスが行えないように設定します。

App Serviceのリソース画面で、左側のメニューから「ネットワーク」を選択します。

右の方にある「受信トラフィック」の中から「アクセス制限」をクリックします。

以下の画面になりますので、「パブリックアクセスを許可する」のチェックを外します。

項目名 設定値
パブリックアクセスを許可する 「チェックあり (許可する)」から「チェックなし (許可しない)」に変更する

設定を変更しましたら、「保存」をクリックします。

設定が反映されるまでしばらくかかるため、待ちます。

設定が反映されましたら、動作確認をしてみます。

WebブラウザでチャットボットのWebアプリへアクセスします。

アクセスが禁止されていることを示す「Error 403 - Forbidden」が表示されます。

もしエラーとならずに正常に表示されてしまう場合は、少し待ってから再度アクセスしてみてください。 それでも駄目なら、ここまでの設定手順を見直してみましょう。

(8) 「App Service」向けの「プライベートエンドポイント」を作成する

こちらもAzure OpenAI Serviceで設定したのと同様に、Azure内部からApp Serviceに対してアクセスできるようにするために「プライベートエンドポイント」を作成します。

App Serviceのリソース画面で、左側のメニューから「ネットワーク」を選択します。

右の方にある「受信トラフィック」の中から「プライベートエンドポイント」をクリックします。

以下の画面になりますので、上部メニューにある「追加」をクリックします。 プルダウンメニューから「Advanced」を選択します。

ウィザード画面に沿って必要な情報を入力して行きます。

項目名 設定値
プロジェクトの詳細 サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
インスタンスの詳細 名前 任意の名前を指定 (例:kumamon-chatbot-ui-endpoint)
ネットワークインターフェイス名 (「名前」欄を入力すると当項目も自動的に設定されます)
地域 Japan East

続いて、プライベートエンドポイントを作成する対象のリソースについて入力します。

項目名 設定値
サブスクリプション リソース作成先のサブスクリプション (変更不可)
リソースの種類 Microsoft.Web/sites (変更不可)
リソース App Serviceのリソース名 (変更不可)
対象サブリソース sites

「App Service」の画面からプライベートエンドポイントを作成する場合、ほとんどの設定項目は既に指定された状態になっているため、改めて指定する必要はありません。

「対象サブリソース」のみ指定可能になっていますが、選択できる値は「sites」しか表示されませんので、必然的にそちらを選ぶことになります。

続いて、プライベートエンドポイントを作成するVNetについて入力します。

項目名 設定値
ネットワーク 仮想ネットワーク 手順(6)で作成したフロントエンドのVNetを選択
サブネット AppSubnet
プライベートエンドポイントのネットワークポリシー 無効
プライベートIP構成 IPアドレスを動的に割り当てる
アプリケーションセキュリティグループ (設定しない)

フロントエンドのVNetを作成する際に作成した2つのサブネットのうち、「AppSubnet」をプライベートエンドポイントの作成先に指定します。

続いて、プライベートDNSゾーンに関する設定項目を入力します。

項目名 設定値
プライベートDNSゾーンと統合する はい
プライベートDNSゾーン 構成名 privatelink-azurewebsites-net
サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
プライベートDNSゾーン privatelink.azurewebsites.net

続いて、「タグ」の設定ページに遷移して、必要に応じてタグの設定を行った後、最後に「確認および作成」へ進んでプライベートエンドポイントの作成を完了します。

(9) 「プライベートDNSゾーン (privatelink.azurewebsites.net)」をVNetへリンクする

App Serviceのプライベートエンドポイントを名前解決するプライベートDNSゾーンを、フロントエンドのVNetへリンクします。

Azureポータル画面を使ってここまでの手順通りに進めた場合、プライベートDNSゾーンが作成された時に自動的にVNetへのリンクも設定されるようです。 自動的に仮想ネットワークリンクが作成されている場合、この手順はスキップして構いません。 もし仮想ネットワークリンクが作成されていない場合は、この手順を行ってください。

「リソースグループ」画面に表示されているリソースの一覧からprivatelink.azurewebsites.netという名前のプライベートDNSゾーンを選択します。

画面左側のメニューから「仮想ネットワークリンク」を選択します。

以下の画面になりますので、「追加」をクリックします。

必要な情報を入力します。

項目名 設定値
リンク名 任意の名前を指定 (例:kumamon-vnet-frontend-link)
仮想ネットワークのリソースIDを知っています チェックを入れない
サブスクリプション リソース作成先のサブスクリプションを選択
仮想ネットワーク 手順(6)で作成したフロントエンドのVNetを選択
自動登録を有効にする チェックを入れない

「OK」をクリックして仮想ネットワークリンクの作成を完了します。

(10) 「DNS Private Resolver」を作成する

App Serviceのプライベートエンドポイントを作成し、プライベートエンドポイントの名前解決を行うプライベートDNSゾーンをVNetへリンクしたことで、VNet内からApp Serviceのエンドポイント (URL) に対してアクセスできるようになりました。

一方、最終的に実現したいのは「Azureと専用線またはVPNで接続されたオンプレミス環境からApp Serviceへアクセスできる」ことです。

プライベートDNSゾーンは「リンクされたVNetからのみ参照できる」という制約があります。 VNetと専用線やVPNで接続されたオンプレミス環境からは、VNetへの通信自体は行えるものの、プライベートDNSゾーンを参照することはできないため、DNS名 (ホスト名) によるアクセスは行えないということになります。

そこで、「Azure DNS Private Resolver」というサービスを用いて、オンプレミス環境からプライベートDNSゾーンを使って名前解決 (DNSクエリ実行) を行えるようにします。

DNS Private Resolverには「受信エンドポイント」と、「送信エンドポイント」があります。

  • 受信エンドポイント: オンプレミス環境からAzureのプライベートDNSゾーンに対してDNSクエリを実行できるようにする
  • 送信エンドポイント: Azure内からオンプレミス環境のDNSサーバーに対してDNSクエリを実行できるようにする

今回は「受信エンドポイント」を使用します。

Azureポータル画面で「すべてのサービス」を開き、カテゴリ「ネットワーキング」にある「DNS Private Resolver」をクリックします。

DNS Private Resolverの画面が開きますので、上部メニューにある「作成」をクリックします。

ウィザード画面に沿って必要な情報を入力して行きます。

項目名 設定値
プロジェクトの詳細 サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
インスタンスの詳細 名前 任意の名前を指定 (例:kumamon-dns-private-resolver)
リージョン (Asia Pacific) Japan East
仮想ネットワーク 仮想ネットワーク 手順(6)で作成したフロントエンドのVNetを選択

続いて、受信エンドポイントの設定画面に遷移します。

「エンドポイントの追加」をクリックします。

以下の画面になりますので、受信エンドポイントの設定項目を入力します。

項目名 設定値
エンドポイント名 InboundEndpoint
サブネット DNSResolverSubnet

「OK」をクリックして、設定を保存します。

続いて、送信エンドポイントの設定画面に遷移します。

今回は送信エンドポイントを使用しませんので、「次」をクリックして次へ進みます。

ルールセットの設定画面に遷移します。

ルールセットとは、送信エンドポイントに対して必要となる設定であり、今回は送信エンドポイントを使用しないため必要ありません。

「確認および作成」をクリックしてDNS Private Resolverの作成を完了します。

環境構築 (その3:オンプレミス環境に見立てた仮想ネットワーク環境を作成する)

ここまでの手順で、「Azure OpenAI Service」と「App Service」をAzure内に閉じたネットワーク環境で利用する構成が完成しました。

最後に、オンプレミス環境に見立てたテスト環境を構築して、最終的な動作確認まで行います。

  • (11) テスト用の「仮想ネットワーク (VNet)」を作成する
  • (12) テスト用とフロントエンドの各VNet同士を「VNet Peering」で接続する
  • (13) テスト用の「Virtual Machine」を作成する
  • (14) テスト用Virtual Machineの「参照先DNSサーバー」を変更する

(11) テスト用の「仮想ネットワーク (VNet)」を作成する

VNetおよびサブネットを作成します。 サブネットは1つだけで十分です。 (画面キャプチャは省略します)

VNetの設定項目:

項目名 設定値
仮想ネットワーク名 任意の名前を指定 (例:kumamon-vnet-test)
開始アドレス 192.168.0.0
ネットワークサイズ /16

サブネットの設定項目:

項目名 設定値
名前 TestSubnet
開始アドレス 192.168.0.0
サブネットサイズ /24

(12) テスト用とフロントエンドの各VNet同士を「VNet Peering」で接続する

VNet同士を接続して相互通信を可能にするサービスが「VNet Peering」です。

VNet Peeringは、接続する各VNetそれぞれで相互に設定を行う必要があります。

  • VNet「A」: VNet「B」へ接続するVNet Peeringを設定する
  • VNet「B」: VNet「A」へ接続するVNet Peeringを設定する

ただし、Azureポータル画面から設定する場合は、どちらか一方のVNetで設定を行うことで、同時に他方のVNet Peeringの設定を行うことができます。

今回は、テスト用に作成したVNetの画面から作成を行います。

VNetのリソース画面で、左側のメニューから「ピアリング」を選択します。

上部メニューから「追加」をクリックします。

以下の画面になりますので、設定項目を入力します。

項目名 設定値
この仮想ネットワーク ピアリングリンク名 PeeringToFrontendVNet
リモート仮想ネットワークへのトラフィック 許可 (規定)
リモート仮想ネットワークから転送されたトラフィック 許可 (規定)
仮想ネットワークゲートウェイまたはルートサーバー なし (規定)
リモート仮想ネットワーク ピアリングリンク名 PeeringToTestVNet
仮想ネットワークのデプロイモデル Resource Manager
リソースIDを知っている チェックしない
サブスクリプション リソース作成先のサブスクリプションを選択
仮想ネットワーク 手順(6)で作成したフロントエンドのVNetを選択
リモート仮想ネットワークへのトラフィック 許可 (規定)
リモート仮想ネットワークから転送されたトラフィック 許可 (規定)
仮想ネットワークゲートウェイまたはルートサーバー なし (規定)

設定項目が多くて入力が大変なように見えますが、

  • 「この仮想ネットワーク」の「ピアリング名」
  • 「リモート仮想ネットワーク」の「ピアリング名」
  • 「リモート仮想ネットワーク」の「サブスクリプション」
  • 「リモート仮想ネットワーク」の「仮想ネットワーク」

をきちんと設定すれば、あとの項目はデフォルト値で問題ありません。

(13) テスト用の「Virtual Machine」を作成する

テスト用のWindows仮想マシンを作成します。

Azureポータル画面で「すべてのサービス」を開き、カテゴリ「コンピューティング」にある「Virtual Machines」をクリックします。

Virtual Machinesの画面が開きますので、上部メニューにある「作成」をクリックします。 プルダウンメニューから「Azure仮想マシン」を選択します。

Virtual Machineの設定項目は非常に多いですが、今回はテスト用ということで、必要最低限の設定のみ行うことにします。

まず、「基本」タブの設定項目を入力します。

項目名 設定値
プロジェクトの詳細 サブスクリプション リソース作成先のサブスクリプションを選択
リソースグループ リソース作成先のリソースグループを選択
インスタンスの詳細 仮想マシン名 任意の名前を指定 (例:kumamon-vm-test)
地域 (Asia Pacific) Japan East
イメージ Windows Server 2022 Datacenter: Azure Edition - x64 Gen2
サイズ Standard_B2s
管理者アカウント ユーザー名 任意のユーザー名
パスワード 任意のパスワード
受信ポートの規則 パブリック受信ポート 選択したポートを許可する
受信ポートを選択 RDP (3389)

イメージ (=OSの種類) は「Windows Server 2022」を選択します。

※ 選択肢の中には「Windows 10 Pro」や「Windows 11 Pro」がありますが、BYOL可能なライセンスを持っている場合のみ利用可能であることに注意してください。

サイズ (仮想マシンのスペック) は、今回はテスト用ですので、比較的安価な「Standard_B2s」を選択しています。

続いて、「ディスク」の設定項目を入力します。

項目名 設定値
OSディスク OSディスクの種類 Standard SSD (ローカル冗長ストレージ)

ディスクの種類は、デフォルトで選択されている「Premium SSD」はテスト用としてはオーバースペックで費用も高いため、コスト優先で「Standard SSD」に変更しています。

続いて、「ネットワーク」の設定項目を入力します。

項目名 設定値
ネットワークインターフェイス 仮想ネットワーク 手順(11)で作成したテスト用のVNetを選択
サブネット 手順(11)で作成したテスト用のサブネットを選択
パブリックIP 「(新規) ~」を選択
NICネットワークセキュリティグループ Basic
パブリック受信ポート 選択したポートを許可する
受信ポートを選択 RDP (3389)

今回は、作成した仮想マシンに対してインターネット経由でRDP接続するために「パブリックIP」を作成します。

ネットワークセキュリティグループは、ここではとりあえず「任意のIPアドレスからRDPでの接続を許可する」設定にします。 警告メッセージが表示されている通り推奨される設定ではありませんが、後ほど対応しますので、ここはこのまま次へ進みます。

今回は「基本」「ディスク」「ネットワーク」の設定のみ行い、残りの「管理」以降の設定は省略します。

「確認および作成」をクリックして仮想マシンの作成を完了します。

ネットワークセキュリティグループの設定変更

仮想マシンの作成が完了しましたら、左側のメニューから「ネットワーク」を選択します。

受信ポートの規則の一覧で「RDP」に注意マークが表示されています。 任意のIPアドレスからのアクセスが許可されているためです。

接続元のIPアドレスに制限をかけて、安全な状態にしましょう。

名前欄の「RDP」をクリックします。

「ソース」の設定値が「Any」となっていますので、これを「My IP address」に変更します。

設定を保存します。 これで、今あなたがアクセスしているIPアドレス以外からの通信を受け付けなくまりました。

(14) テスト用Virtual Machineの「参照先DNSサーバー」を変更する

これが最後の手順です。

テスト用の仮想マシンからApp ServiceのWebアプリへアクセスを行う際に、手順(10)で作成したDNS Private Resolverの受信エンドポイントに対してDNS名前解決を行う必要があります。

本番運用の環境であれば、通常は、オンプレミス環境の社内DNSサーバーに対して「条件付きフォワーダー」の設定を行うことになります。

ただ今回はテストですので、テスト用の仮想マシンからDNS Private Resolverの受信エンドポイントを直接参照するように設定して、DNS名前解決が行えるようにしましょう。

設定前のDNS名前解決の動作

設定を行う前に、DNS Private Resolverを参照しない場合のDNS名前解決の動作を確認してみましょう。

テスト用の仮想マシンへリモートデスクトップ接続クライアント (RDPクライアント) を使って接続します。

コマンドプロンプト (またはPowerShellコンソール) を起動して、以下のようにコマンドラインを実行します。

> nslookup kumamon-chatbot-ui.azurewebsites.net (※DNS名は皆さんの環境に合わせて変更してください)

すると、以下のように結果が返ってきました。

Server:  UnKnown
Address:  168.63.129.16

Non-authoritative answer:
Name:    XXXX-XXXX-XXX-XXX-XXXX.japaneast.cloudapp.azure.com
Address:  20.210.XXX.XXX
Aliases:  kumamon-chatbot-ui.azurewebsites.net
          kumamon-chatbot-ui.privatelink.azurewebsites.net
          XXXX-XXXX-XXX-XXX.sip.azurewebsites.windows.net

まず、問い合わせ先のDNSサーバーのアドレスとして表示された「168.63.129.16」ですが、これはMicrosoft Azureが提供するDNSサーバーのアドレスです。 このDNSサーバーは、Azure上の仮想マシン等がインターネット上のDNS名を名前解決する際に用いられます。

そして、名前解決の結果として表示されたIPアドレスは「20.210.XXX.XXX」となりました。 つまり、インターネット上のグローバルIPアドレスが返ってきたということになります。

仮想マシンからこのIPアドレスに対してアクセスしようとすると、インターネット経由でApp Serviceへアクセスすることになります。 App Serverの設定で「インターネット経由でのアクセスは拒否する」ようになっていますので、これではWebアプリへアクセスすることができません。

参照先DNSサーバーの設定を変更する

それでは、仮想マシンの「参照先DNSサーバー」の設定を変更しましょう。

DNS Private Resolverの画面から「受信エンドポイント」のIPアドレスを確認しておきます。

仮想マシンのネットワーク設定から「TCP/IPのプロパティ」(Internet Protocol Version 4 (TCP/IPv4) Properties) を開きます。

「優先DNSサーバー」(Preferred DNS Server) 欄に、上記で確認した「DNS Private Resolverの受信エンドポイントのIPアドレス」を設定します。

設定後のDNS名前解決の動作

再度、以下のようにコマンドラインを実行します。

> nslookup kumamon-chatbot-ui.azurewebsites.net (※DNS名は皆さんの環境に合わせて変更してください)

今度は以下のように結果が返ってきました。

Server:  UnKnown
Address:  10.1.1.4

Non-authoritative answer:
Name:    kumamon-chatbot-ui.privatelink.azurewebsites.net
Address:  10.1.0.4
Aliases:  kumamon-chatbot-ui.azurewebsites.net

問い合わせ先のDNSサーバーのアドレスが「DNS Private Resolverの受信エンドポイントのIPアドレス」になっていることを確認します。

名前解決の結果として表示されたIPアドレスが、さきほどと異なりプライベートIPアドレスになっていることが分かります。 このアドレスは「App Serverのプライベートエンドポイント」のIPアドレスです。

このメカニズムによって、App ServerのWebアプリに対してAzure内部ネットワーク経由でアクセスすることができるようになりました。

動作確認

仮想マシン上でWebブラウザ (Microsoft Edgeなど) を起動して、App ServiceのWebアプリのURLへアクセスします。

前回のブログ記事で「Azure ADによる認証を設定する」を行っている場合は、以下のようにAzure ADのサインイン画面が表示されます。 (認証を設定していない場合、この画面はスキップされます)

サインインを行うと、Chatbot UIの画面が表示されました。

OSのロケールが米国であるため表示が英語になっていますが、日本語で質問すると、ちゃんと日本語で回答が返ってきます。

長丁場になりましたが、これで一連の設定の手順と、動作確認が終わりました!

あとかたづけ

構築した環境を削除するには、通常であれば「作成した時と逆の順番でリソースを削除する」というのがセオリーですが、今回の場合は以下の順番で削除するのがスムーズに削除できるのではないかと思います。

  • 仮想マシン、App Serviceなど、機能を提供するサービス (いわゆる「上物」)
  • ネットワーク系のサービス
  • 仮想ネットワーク (VNet)

具体的には、以下の順番で各リソースを削除します。

  • 「Virtual Machine」を削除する
    • 仮想マシンを削除 (「OSディスク」「ネットワークインターフェイス」「パブリックIPアドレス」も併せて削除する)
    • 仮想マシンに割り当てられていた「ネットワークセキュリティグループ」を削除
  • 「App Service」を削除する
    • 「App Service Plan」も併せて削除する
  • 「Container Registry」を削除する
  • 「Azure OpenAI Service」を削除する
    • 先に「デプロイモデル」を削除しておく必要があります (Azure OpenAI Studio画面から)
  • 「DNS Private Resolver」を削除する
    • 先に「受信エンドポイント」を削除しておく必要があります
  • 「プライベートエンドポイント」を削除する
    • App Service用のプライベートエンドポイントを削除
    • Azure OpenAI Service用のプライベートエンドポイントを削除
  • 「プライベートDNSゾーン」を削除する
    • プライベートDNSゾーン「privatelink.azurewebsites.net」を削除
      • 先に「仮想ネットワークリンク」を削除しておく必要があります
    • プライベートDNSゾーン「privatelink.openai.azure.com」を削除
      • 先に「仮想ネットワークリンク」を削除しておく必要があります
  • 「VNet」を削除する
    • テスト用のVNetを削除
    • フロントエンドのVNetを削除
    • バックエンドのVNetを削除

削除が上手く行かない時は、しばらく待ってみてから、再度削除を試みると成功することが多いです。

おわりに

Azure OpenAI ServiceをAzureに閉じたネットワーク環境に構築・利用する方法についてご紹介しました。

今回の構成は、かなり複雑なものになりました。 また、サービス間の依存関係もやや複雑になっていますので、注意しないとそこで詰まるかもしれません。

それでも、一つ一つのサービスが何を行っているのか・何のために作成するのかを確認しながら構築を進めて頂ければ、理解が深まるのではないかと思います。

この構成をベースに、Azureのネットワーク関連やセキュリティ関連のサービスを組み合わせて、よりセキュアな構成にするというのも良いのではないでしょうか。