Azure Static Web Apps へプライベートエンドポイントを適用してみる

## はじめに
Azure Static Web Apps にて、プライベートエンドポイントを追加できる機能がパブリックプレビュー（2021 年 8 月 18 日現在）となりましたので実際にその機能を使用してみた内容を書いていきます。

[Azure Static Web Apps adds public preview support for Private Endpoints](https://azure.microsoft.com/en-us/updates/azure-static-web-apps-adds-public-preview-support-for-private-endpoints/)
> Azure Static Web Apps has added preview support for Private Endpoints. Private Endpoints enable you to access your static web app through an IP address located in your Azure Virtual Network (VNet), eliminating exposure to the public internet. Private Endpoints are supported in the Static Web Apps Standard plan. 

プライベートエンドポイントを有効にすると、インターネット上からプライベートエンドポイントが適用された Azure リソースへの通信を遮断し、Azure Virtual Network (VNet) のみ通信を許可することができます。
Azure Web Apps や Azure Functions には、プライベートエンドポイントを有効にする機能があり、インターネット上である外部との通信を遮断することができましたが、今回は Static Web Apps にも同様の機能が発表されたため、外部に公開したくない静的ページなどがある場合には便利な内容だと考えてます。

詳しい内容は、Static Web Apps のドキュメントがありましたので貼っておきます。
[Configure private endpoint in Azure Static Web Apps](https://docs.microsoft.com/ja-jp/azure/static-web-apps/private-endpoint)

## Azure Static Web Apps へアプリケーションをデプロイ
こちらのチュートリアルを使用して、Azure Static Web Apps を作成する際にサンプルコードを利用してデプロイをしていきます。Azure Static Web Apps をデプロイするには、最低でも 1 つの HTML ファイルが必要となるためサンプルコードを利用することで簡単にはじめることができます。

[クイックスタート: Azure Static Web Apps を使用して静的サイトを初めて構築する](https://docs.microsoft.com/ja-jp/azure/static-web-apps/getting-started?tabs=vanilla-javascript)

### Azure Static Web Apps の作成
Azure Portal から Azure Static Web Apps の作成を行います。Azure Portal 上部のメニューバーより検索を行い作成画面へ移動します。
対象のサブスクリプション、リソースグループを選択し、任意の Azure Static Web Apps 名を指定した後に、今回は以下のスクリーンショットのように設定値も指定します。

- プランの種類：Standard
- Azure Functions とステージング環の詳細：East Asia
- ビルドのプリセット：Custom
- アプリの場所："/"

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/c4f32c14-2207-b46f-5ed7-146a6a83aafe.png)


使用しているサンプルコードは以下の GitHub のリポジトリから新しく自分の手元にリポジトリを生成しております。Index.html と styles.css のみが入ってます。
https://github.com/staticwebdev/vanilla-basic


### 確認をする
Azure Static Web Apps へのデプロイ後に、デフォルトで付与された URL へ接続を行い無事に GitHub のリポジトリに格納されたファイルが閲覧できるか確認を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/25d59394-764b-2fe3-a48c-8c3b05bdd896.png)


## プライベートエンドポイントを Azure Static Web Apps へ適用

### VNet の作成
Azure Static Web Apps のプライベートエンドポイントの画面からでは、新規に VNet やサブネットを作成することができなかったので、あらかじめ VNet を作成してから適用をしていきます。
今回は VNet をデプロイするリージョンを 東日本にしていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/5d7ec4fa-94fa-0495-a708-ea6105cacd24.png)


VNet 内に作成するサブネットの内容も何も変更せずに default としていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/c1024732-a200-a317-73e7-23aa85fca707.png)


### プライベートエンドポイントを適用
さて、いよいよ本題のプライベートエンドポイントを適用していきます。
Azure Portal の左メニューから、 `プライベートエンドポイント（プレビュー）` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/b54c0c73-04f4-544c-460b-cb146fa8566f.png)


上部にある 追加 ボタンを押して、右側から設定画面が表示されます。
プライベートエンドポイント名を指定して、先ほど作成した VNet とサブネットを指定します。
プライベート DNS ゾーンと統合するには、 はい を選択します。はい を選択することで、Azure Private DNS ゾーンが作成され、プライベートエンドポイントに関するレコードが自動で追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/c6a47c15-0386-e845-7318-710a5eee9c0c.png)


プライベートエンドポイント、Azure Private DNS の作成があるため、数分間待つ必要がありますが、無事に適用が完了されるとプライベートエンドポイント接続に表示されていることを確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/0a3acfb1-7c9d-bcbc-a2a3-876ad3164def.png)


## 接続テスト
### インターネットから Azure Static Web Apps へ接続
自分のローカル PC のブラウザから、Azure Static Web Apps へ接続をしてみましょう。
Azure Static Web Apps の画面が表示され、403: Forbidden が出力されていることが分かります。
また、ステータスコードを確認すると、HTTP Status 403 でしたので、インターネットからの通信は遮断されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/0e5fd98d-a0f3-b99e-c347-72232808ec8a.png)


### VNet 内のリソースから Static Web Apps へ接続
VNet 内に Virtual Machine (VM) を作成を行い、VM から Azure Static Web Apps への接続を行います。
以下のスクリーンショットは、VM のブラウザより Azure Static Web Apps へ接続した内容となります。インターネットからの接続は遮断されておりましたが、VNet 内のリソースからは正常にコンテンツが閲覧できることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/1c2aeece-4301-4930-ee92-478a1146f294.png)


### プライベート IP アドレスを利用した接続はできない
Azure Private DNS にて、Static Web Apps へ接続されたプライベートエンドポイントのレコード情報を確認することができます。内容を確認すると、Azure Static Web Apps の FQDN と A レコードでプライベート IP アドレスが紐づいています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/11d592cf-529e-8769-0c12-56d5734502e5.png)


それでは、そのプライベート IP アドレスを利用して、VM のブラウザからアクセスした場合は正常に、Azure Static Web Apps のコンテンツは閲覧できるか試してみましょう。
プライベート IP アドレスを用いて接続をすると、HTTP Status 400 が返却され、Bad Request - Invalid Hostname が出力され正常に Azure Static Web Apps のコンテンツを閲覧することはできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/54adc1f3-bcac-5f35-2d6b-4389da8e69e5.png)


Invalid Hostname が出力されたため、Azure Web Apps や Azure Function と同様に IP アドレスでの接続は行えないです。Host ヘッダを利用して Azure Static Web Apps へ接続を行っているため、curl コマンドを利用してプライベート IP アドレスでの接続を行う場合には、以下のコマンドを実行することで実現可能になりました。以下のスクリーンショットは、VM 内のコマンドプロンプトの curl コマンドを実行しているので、各環境に合わせた curl コマンドへの変更が必要となる場合があります。

> $ curl -I -L <プライベート IP アドレス> -H "Host:<Azure Static Web Apps のデフォルトのホスト名>"

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/f24098b1-b16c-7cbc-6dc3-5bad39aeac10.png)



## デプロイのテスト
プライベートエンドポイントが有効の状態で、GitHub のソースコードを変更した際の挙動を確認していきます。
あらかじめ Azure Static Web Apps へ接続している GitHub の Index.html の内容を変更していきます。コンテンツ内に記載している `Vanilla JavaScript App` の文字列を `Vanilla JavaScript App Ver.2` へ変更します。
GitHub Actions のビルドログを確認するとアクセス制限などは発生しておらず、無事に Azure Static Web Apps へのデプロイが正常に完了しておりました。
VM 内のブラウザから Azure Static Web Apps へアクセスすると更新した内容が反映されていることが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/8bcbcb8b-9d72-f870-123d-d0eef8b72a29.png)


## おわりに
今回は Azure Static Web Apps にプライベートを追加して、それぞれの環境からの接続テストを実施しました。インターネット経由からの接続を行うと HTTP Status Code 403 が返却され閲覧はできませんでした。一方で VNet 内の VM から接続は行うことができ、Azure Web Apps, Azure Functions と同様に FQDN の名前解決を使用します。
また、GitHub リポジトリ内のコンテンツの変更を行い、push をしてもプライベートエンドポイントとは影響しておらず正常に更新することができました。
Azure Static Web Apps で作成した内容に対して、外部から直接閲覧されたくない静的なコンテンツがある場合には、1つのアクセス制限として有効な機能であるのと感じました。