Azure OpenAI Serviceを拠点から閉域で使う方法

# はじめに
Azure OpenAI Service（以下、AOAI）が流行ってますね！昨今ではエンタープライズ利用の話もよく聞きます。私の周りのお客様からも「とりあえず触ってみたい」という声が出てくるようになりました。ひとまず使いたいということであれば、Azure環境があれば、そのサブスクリプションについてAOAI利用申請を上げることで、すぐに使えるようになります。（私の場合も即日承認メールが届きました。）
しかし、エンタープライズでの本格利用となると、他のAzureサービスと同様にセキュリティやネットワーク経路に気を遣う必要があります。これから色々な観点で検証をしてみたいと思いますが、今回はネットワークの観点でお客様の拠点やオンプレミス環境からAOAIを安全に使うための方法を試してみました。

# まずは AOAI のネットワーク制限
AOAI自体にネットワーク制限かけたい場合に、どのような機能が使えるか挙げてみます。

## AOAI の Firewall
まず、AOAIは他のAzureサービスと同じくFirewall機能を持っています。Firewallを有効化することで、AOAIのアクセス元制限を行うことができます。一般アクセスをDenyして、アクセス許可する（Azure内の）VNET、もしくはパブリックIPを設定することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/a44529b7-5b2a-c17d-16b5-344645d04f99.png)

また、このFirewallが偉いのは、この設定を入れることでAOAIのAPIを受付元を制限するだけでなく、 **「Azure OpenAI Studio」の方もアクセスを制限してくれる** ことです。厳密には「Azure OpenAI Studio」自体にアクセスはできてしまいますが、プロンプト入力は拒否されますので実質利用することができなくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/4e303e4c-4e2f-5f9c-dcd1-49c0e03bf4ab.png)

ただ、ネットを見ていると全ての操作ができなくなる訳ではないようなので、入口からアクセスを防ぎたい場合は **AzureADの条件付きアクセス** を適用するのがよいと思います。(未検証)


## AOAI の PrivateEndpoint
AOAIリリース当初からPrivateEndpointを入れてくるあたり、Microsoftもエンタープライズ利用を想定しているんだと察しました。AOAIのPrivateEndpointについては、すでにたくさんの方がブログ等で書かれているので、もはや三番煎じくらいですが、PrivateEndpointを構成することでAOAIのアクセスにはVnet内のプライベートIPを使うことができますので、パブリックネットワークに出ることなくAOAIを利用することができます。

AOAI側の設定はこんな感じになります。PrivateEndpointを構成すると、PrivateEndpoint専用NICやプライベートDNSゾーンが構成されますが、そのあたりの詳細は割愛します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/17ab507c-b381-0b20-f478-8bbd18e4b411.png)

## NSG(Network Security Group)
NSGはもう誰もが使ったことがある一般的なサービスですが、先ほどのPrivateEndpointが所属するSubnetにもNSGを効かせることができるようになっています。NSGの範囲で更にアクセス制御をかけることでセキュリティを高めることが可能です。

# 更なる拡張に向けて
AOAIのFirewall、PrivateEndpointさらにはNSGを利用すると下記の構成を作ることができます。これでだいぶセキュアな環境ができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/7d98354d-a83f-1978-b1ce-a2606b7fa298.png)
さて、ここまではAzureに閉じた話なのでそんなに難しくありません。しかし、実際の現場でAOAIがどのように使われるか考えた場合、Azure内のVMからしか使えないというのは現実的ではありません。実際は、お客様の拠点やオンプレミス環境の業務システム（APサーバ）、もしかしたら他クラウド上のサーバからAOAIに繋ぎたい、という要件が出ると思われます。

## DNS Private Resolver
Azure外からPrivateEndpointに接続する際に問題になるのは、名前解決です。拠点やオンプレミス環境とはExpressRouteやVPNで接続することでIP Reachableになりますので、PrivateEndpointのプライベートIPにアクセスことは可能になりますが、プライベートDNSゾーンにはアクセスできませんので、URLで接続する際にはこのプライベートIPを誰が名前解決してくれるのか、という問題がでます。この時に使えるのがDNS Private Resolverです。
DNS Private Resolverはオンプレミス環境からAzure DNSプライベートゾーンに対してクエリが発行できるようになるサービスです。細かなアーキテクチャは下記をご参照ください。

https://learn.microsoft.com/ja-jp/azure/dns/dns-private-resolver-overview

兎にも角にも先ほどの環境にDNS Private Resolverを導入することで、下記の構成を実現できます。お客様の拠点からもセキュアにアクセスできますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/7e9b0380-e819-269c-3dca-bbd25a9602b8.png)

# 実機確認してみた
上記構成を実際に作ってみました。ExpressRouteは個人で使える環境がないので、P2SのVPNを構成しました。メインどころのリソースの構成をざっくり紹介します。

## AOAI
Firewallは”許可するアクセス元”を「無効」とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/1be2a8d7-fee2-55f3-70eb-6c948629d46b.png)

PrivateEndpointは中継するVnetと繋がっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/05e532b9-f9f4-8b8f-9b69-3b4ecf1064f9.png)

## 中継VNET
サブネット構成は以下の通り
* GatewaySubnet・・・P2SVPNを繋ぐVnetGateway用
* snet-inbound・・・DNS Private Resolverのインバウンド側
* snet-outbound・・・DNS Private Resolverのアウトバウンド側
* delegatedSubnet・・・AOAIのPrivateEndpoint用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/b07db3cb-f60f-fad0-c003-5f62e31fa26f.png)

接続デバイスは以下の通り
* aoai-vpn-gw・・・ P2SVPNを繋ぐVnetGateway
* aoai-priateendpoint-nic・・・AOAIのPrivateEndpoint用のNIC
* lbi-prod-japaneast-main-ept・・・DNS Private Resolver用のロードバランサ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/d638febe-2b15-d3be-7571-e564a496c67b.png)

## VnetGateway
今回はVPNクライアントはOpenVPNを選択しました。VPN関連の設定は割愛しますが、一通りの設定をいれてVPN接続を確立できる状態になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/7faa2c76-6066-a226-58a2-dbadc0a6231c.png)

## 実機確認結果

### VPN未接続時
まずVPNに繋いでいない状態でnslookupでAOAIの名前解決を実行してみます。すると当然ですがパブリックなIPが引かれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/df900c15-1ea8-bad1-205a-430389820aa8.png)

AOAI側はFireweallで外部からの接続を拒否しているため、この状態でAOAIに向けてAPIを実行しても”Public access is disabled.”と言われエラーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/cc5af8b7-c78d-4be6-6ead-0852a476367f.png)

### VPN接続状態
次にVPNを繋いでみます。VPNのNIC状態は以下のようになります。アドレスがVnetGatewayのアドレスプールから払い出されていることと、DNSがDNS Private Resolverに向いていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/d520075d-1ac8-54b9-f3ec-31b2b3669453.png)

この状態で再びnslookupでAOAIの名前解決を実行してみます。すると今度はPrivateEndpointのプライベートIPが引かれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/3fec5097-9c9a-f7ec-53f6-a2b9445ab46b.png)

さらにAOAIに向けてAPIを実行します。するとステータスコード：200が返ってきて正常に接続していることを確認できました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199489/edd1430e-8b58-ffd1-1cd6-0adb19098df2.png)

# おわりに
今回はAOAIを拠点から閉域で使う方法を実際に試してみました。搭乗するAzureサービスが増えますので多少コストに跳ねますが、全てマネージドサービスで構成することができましたので運用観点で楽ができるかと思います。是非参考になれば幸いです。それではまた！