Power Platform の Azure Virtual Network サポートを試してみた


# はじめに

以前、以下のような記事を書いたのですが、残念ながら、こちらの機能のプレビューが取り下げられたようで、Power Platform から Azure OpenAI に対する通信について、パブリックな通信になってしまう (通信自体は、マイクロソフトのバックボーンネットワークを通る認識ですが、Azure OpenAI 側では、以下のように、すべてのネットワークを許可している必要がある) ため、本番利用にあたって、セキュリティ面で少なからず課題がありました。

https://qiita.com/Takashi_Masumori/items/a2c716c8529aca9993ef

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/e6823eb4-5d88-25a3-99e3-fd3173b7b48a.png)

:::note
もちろん、AI Builder の AI プロンプトを利用する場合、Copilot Studio の生成 AI 機能のデータソースとして SharePoint Online やファイルのアップロードを利用する場合、Azure OpenAI との通信はセキュリティが保証されているため、特に心配する必要はありません。実際には Azure OpenAI の技術がバックエンドで利用されていますが、Azure OpenAI 側でリソースを用意し、モデルをデプロイする必要はないためです。
:::

https://qiita.com/Takashi_Masumori/items/07aba9675f3cf576b393

https://qiita.com/Takashi_Masumori/items/173cb84a860b491f885b

https://qiita.com/Takashi_Masumori/items/359ba52e5db2ca862d94

:::note 
しかし、利用したいモデル、機能によっては、Power Platform から Azure OpenAI の API を直接利用したいというケースがあるという認識です。

例えば、以下の機能では、gpt-4 モデルを利用しており、ハイブリッド (ベクトル + キーワード) + セマンティックベクトル検索を有効にしているため、以下のように、独自の文章の意味を元に回答を得ることが出来ます。そのため、Copilot Studio の生成 AI 機能では十分な精度が出ない場合、こちらの機能を利用することが代替案となるかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/be664f7a-aad0-c463-0932-f7d6da7b6f61.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/1ed94a5a-0976-e8a7-53e4-ef76595b050e.png)

現状、ベクトル検索は、Copilot Studio の生成 AI 機能ではサポートされていないようなので、例えば、Copilot Studio から、Power Automate を介して、こちらの API を利用するカスタムコネクタを介してリクエストをする、かつ、Azure Virtual Network を利用してプライベートエンドポイント経由にするのが個人的に良いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/b7dd2b15-ab81-48f2-5e37-c772038921e6.png)

:::

上記のような背景を踏まえ、今回は、こちらの機能がパブリックプレビューとなったため、試してみました。

https://learn.microsoft.com/ja-jp/power-platform/admin/vnet-support-setup-configure#set-up-the-virtual-network-and-subnets

https://qiita.com/Isato-Hiyama/items/08cdca65f2abad9f8757#3power-platform-%E5%81%B4%E3%81%AE%E8%A8%AD%E5%AE%9A

結論から言うと、以下の記事 (特にブログの方) を参考に色々試してみたのですが、上手く行かなかった、具体的には、プライベートエンドポイントのみから通信を許可するようにしたのですが、以下のようなエラーとなり、カスタムコネクタを利用したリクエストに失敗してしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/bfc9cc39-b464-4366-8b9d-33f9fa92ee73.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/ae385fb6-51eb-f47c-0cec-7913e95515cb.png)

パブリックプレビューのため動作が安定しない、何らかの制約があるのかもしれませんが、どこか設定に誤りがある場合、アウトプットすることで、その原因を知れるかもしれないことや、実際に試すことで少なからず学んだことがあるので、一応記事に残しておこうと思います。

# Azure OpenAI 準備作業

East US にリソースを作成し、モデルをデプロイします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/77757283-e381-b096-1338-6674177299e2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/04a3dbe9-85d8-16df-7fc6-ee4cd63298c3.png)

先に、AI Serarch 側でインデックスを作成しておき、on your data で利用できるようにしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/38c3ad31-9e40-6b40-e5ca-231b2634c5cf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8be09c87-ba3d-8719-05d5-4d6126301026.png)

# Virtual Network の作成

Power Platform からの通信を受け付ける Virtual Network を East US と West US に作成しておきます。
また、Azure OpenAI リソースのプライベートエンドポイント用にも Virtual Network を作成しておきます。
以下のようにピアリングの設定もしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/ddc668c4-2708-e578-35bd-f19e42f34c02.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/35e04b37-58ed-3d1d-bfc6-5373d728da19.png)


# サブネットの委任設定

Power Platform からの通信を受け付ける Virtual Network のサブネットにて ( East US と West US の両方)、以下の設定を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d140d097-f104-b581-7c6f-07833b11bbe5.png)

# Enterprise Policy の作成

https://github.com/microsoft/PowerApps-Samples/tree/master/powershell/enterprisePolicies#1-setup-virtual-network-for-subnet-injection

今回初めて実行しますが、上記からダウンロードしたファイルの .\CreateSubnetInjectionEnterprisePolicy.ps1、.\NewSubnetInjection.ps1 PowerShell スクリプトを実行し、Enterprise Policy の作成、環境との紐づけを行いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/e467e2ed-92fe-ce7f-867a-4d9839ef59e3.png)

上述のブログを参考にしたのですが、私の環境の場合、いくつかのテナントにゲストアカウントで入っていることもあり、EnterprisePolicyOperations.ps1 と EnvironmentEnterprisePolicyOperations.ps1 ファイルについて、以下のように、Connect-AzAccount コマンドにて、明示的に自分のテナントを指定しないとコマンドが失敗しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d1ae8a44-2d1b-a73f-e58d-b2e48a21ad41.png)

スクリプト内で Connect-AzAccount コマンド実行していますが、明示的にテナント ID を指定していないと、自分のテナントだけでく、ゲスト参加しているテナントにも接続しようとしているように見受けられます。

```
警告: Unable to acquire token for tenant 'ゲスト参加しているテナント ID' with error 'SharedTokenCacheCredential
authentication unavailable. Token acquisition failed for user *****. Ensure that you have
authenticated with a developer tool that supports Azure single sign on.'
```

今回、米国環境を作成しており、以下からは成功しているように見えます。
※何度かポリシー作成して割り当ての変更も行いました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d7482aae-b305-d859-e56e-698904c81787.png)

# 検証

まず、一旦は、以下の設定にして、HTTP コネクタやカスタムコネクタで動作することを確認します。最終的には、Enterprise Policy を紐づけている環境、かつ、現状サポートされているカスタムコネクタからのみ通信が成功する想定です。個人的には将来的に HTTP コネクタがサポートされたら嬉しいですが。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8484a17f-4df4-62de-b6db-710f3f552f13.png)

on your data のデータソースを元にした回答が返ってきました。ベクトル検索の効果もあり、年休という単語でも、有給休暇に関する情報が返ってきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/028fb6a1-4f7c-94c2-0af5-0d65bc9642ea.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/7632737e-b49c-44d3-492d-1904cfc6b1d0.png)

次に、プライベートエンドポイントを作成し、許可するアクセス元の設定を無効にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/932fb7af-180e-ee34-9758-c87f35eb8d8e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/34fdd7ea-44f2-f968-3f4a-6ca0c64527ce.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/926820c5-47c9-9a16-7428-5d7c62a0f498.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8b5fba9e-dfd3-885e-58e0-cfe4fdee63c1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8e5b2020-02bc-dc83-69bb-b23df270e0e8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/c88d4346-0352-273b-8e2f-10b0883b203d.png)

プライベート DNS ゾーンにて、Power Platform からの通信を受け付ける Virtual Network 2 つをリンクに追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d0bf19a5-6353-582e-8d5a-87bcbb70425f.png)

再度テストしたところ、HTTP コネクタだけでなく、カスタムコネクタについても失敗してしまいました。設定を元に戻すと成功するので、残念ながら、Azure Virtual Network を介して Azure OpenAI リソースのプライベートエンドポイントに対して接続が上手くできていないようです。あまりこの辺のインフラ回り詳しくないこともあり、どこか設定に問題があるのか、パブリックプレビューということで、環境や Azure のリソースのリージョンなどの影響で動作が安定していないのかよく分からず、また、具体的に通信のどの段階で失敗しているのかまでは分かりませんでした。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/b87d181e-e23c-c32c-c498-ea0b009b7d2c.png)

```
{
  "error": {
    "code": "403",
    "message": "A Virtual Network is configured for this resource. Please use the correct endpoint for making requests. Check https://aka.ms/cogsvc-vnet for more details."
  }
}
```

# (補足) on your data を API で利用する

以前以下の記事を書いたのですが、久しぶりに利用すると、結構変わっていました。

https://qiita.com/Takashi_Masumori/items/410e7e92e6f93ec823c2

まず、プレイグラウンドに表示される json を利用してもいいと思いますが、リファレンスと結構違ってパラメーターが多かったので、とりあえず、以下のような Body でリクエストをしました。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/concepts/use-your-data?tabs=mongo-db

https://learn.microsoft.com/en-us/azure/ai-services/openai/references/azure-search?tabs=rest

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/79533a4f-4596-9955-86df-2f6fa22fa57b.png)

```
{
  "data_sources": [
    {
      "type": "azure_search",
      "parameters": {
        "endpoint": "https://*****.search.windows.net",
        "index_name": "vector-1714517262881",
        "authentication": {
          "type": "api_key",
          "key": "*****"
        }
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "年休取得方法を教えて"
    }
  ]
}

```

一応、上述の通り、問題なく動作しています。必要に応じて、独自データを元に、ハイブリッド検索して回答を返してくれるので、社内で ChatGPT を使えない、独自データも精度良く回答を返してほしいといったケースにおいて、Power Platform (フロントエンドを Power Apps にしたり、Copilot Studio にしたり) にするアプローチについて、引き続き需要あるかと思います。

# (補足) 作成したリソースの削除

検証でちょっと試してみる場合、Virtual Network など、作成したリソースの削除処理が面倒です。私が慣れていないのもありますが、依存関係のあるリソースを削除しないと削除に失敗します。
例えば、Enterprise Policy については、環境との紐づけを解除し、その上で、以下コマンドで削除する必要がありました。その上で、Virtual Network のサブネットで委任を削除し、サブネットを削除し、Virtual Network 自体を削除する必要がありました。
なお、環境が削除されていると、そもそも紐づけが解除できないため、Enterprise Policy リソースの削除自体もできず、結果として、Virtual Network の削除も出来ない認識です。

```
PS C:\PowerApps-Samples-master\PowerApps-Samples-master\powershell\enterprisePolicies\SubnetInjection> Remove-AzResource -ResourceId "/subscriptions/*****/resourceGroups/OpenAITestResourceGroup/providers/Microsoft.PowerPlatform/enterprisePolicies/pp-vnet" -Force
Remove-AzResource : EnterprisePolicyDeleteNotAllowed : Enterprise Policy Deletion not allowed for Enterprise Policy with name pp-vnet as it is linked with
1 environment with environmentId as 1b181271-cbaf-ea99-ad83-4a8cc6c3230b. Please unlink these environments from Enterprise Policy name pp-vnet and id 0b120
320-db50-4952-9455-f6c2a561b6b5 to perform deletion
CorrelationId: 8118a621-bd33-4702-873a-7de60c45e47b
発生場所 行:1 文字:1                                                                                                                                        + Remove-AzResource -ResourceId "/subscriptions/***** ...                                                                                 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                                         + CategoryInfo          : CloseError: (:) [Remove-AzResource]、ErrorResponseMessageException                                                                + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.RemoveAzureResourceCmdlet
```

```
PS C:\PowerApps-Samples-master\PowerApps-Samples-master\powershell\enterprisePolicies\SubnetInjection> .\RevertSubnetInjection

コマンド パイプライン位置 1 のコマンドレット RevertSubnetInjection
次のパラメーターに値を指定してください:
environmentId: *****
policyArmId: /subscriptions/*****/resourceGroups/OpenAITestResourceGroup/providers/Microsoft.PowerPlatform/enterprisePolicies/pp-vnet
Logging In...
Logged In...
Error getting environment with ***** for endpoint prod Error = @{StatusCode=404; StatusDescription=Not Found; Headers=Strict-Transport-Security: max-age=31536000; includeSubDomains
x-ms-islandgateway: ga0000001
x-ms-request-id: japanwest:21198c4c-2589-4495-8ee3-1c04583f70cb
x-ms-correlation-request-id: 8356d385-bc7b-413d-87d8-25daeb19fb21
x-ms-correlation-id: 8356d385-bc7b-413d-87d8-25daeb19fb21
Server-Timing: x-ms-igw-upstream-headers;dur=328.7,x-ms-igw-req-overhead;dur=1.1
X-Content-Type-Options: nosniff
x-ms-service-request-id: 171d9f2b-145d-4c55-9f2c-ef78f5caa91a
x-ms-activity-vector: 00
Content-Length: 211
Cache-Control: no-cache, no-store
Content-Type: application/json; charset=utf-8
Date: Thu, 02 May 2024 00:19:05 GMT

; Error=; Message=The environment '1b181271-cbaf-ea99-ad83-4a8cc6c3230b' could not be found in the tenant '*****'.; Internal=System.Net.HttpWebResponse}
```

# まとめ

今回は、上手く行きませんでしたが、Power Platform の Azure Virtual Network サポートを試してみた内容について整理しました。

正直、Azure のインフラ回りに慣れていないと敷居が高く、パブリックプレビューという位置づけからも、個人的には、現状は、本番運用で利用するのは厳しいかなと思いますが、アプローチとしては絶対必要な機能だと思うので、今後の機能の進化に期待したいです。そして、私の手元でも動いて欲しいです。。

また、設定難易度やセキュリティ面の課題を考慮すると、フュージョン開発であれば別ですが、市民開発者の方が、生成 AI 技術を利用した独自のアプリや自動化フロー、チャットボットを作成できるよう広く開放する場合は、AI Builder、Copilot Studio を利用する方が良いと思います。そのため、これらの機能の進化 (取り急ぎ、AI モデルや検索精度向上辺り) にも期待したいです。

※あと、これは完全な主観ですが、個人的に カスタムコネクタの作成エクスペリエンスあまりよくなく、API キーを使う場合においても、HTTP コネクタと比較すると、動作不安定な印象があります。例えば、同じエンドポイントに同じリクエストをしている場合においても、急によくわからない応答が返ってくることがあります。以下は、"Request Header Fields Too Large"ですが、それ以外にも、"Bad Gateway"、"Resource not found"といったエラーが返ってきて動かなくなることがありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/5c2c8716-00b6-0a8b-1fe3-5c6cb92ded7e.png)