Azure Cloud Shell プライベート環境、エフェメラルセッション

Azure Cloud shell はブラウザ経由で Bash または Powershell を実行する環境を提供するもので、Cloud Shell を利用することで手元のクライアント端末に Azure Powershell や Azure CLI のモジュールをインストールせずにコマンドを実行することができます。

また、ブラウザにログインしたユーザーで自動的に認証されるため、Azure の操作目的であれば PC からの利用より便利に使えることが多いです。Azure 以外の操作ではモジュールの追加が必要等で使えないことがあります。

以前はプライベート化されたリソースへのアクセスはサポートされていませんでしたが、仮想ネットワーク上のリソースへのアクセスもサポートされるようになりましたので、手順や留意点をまとめております。

https://learn.microsoft.com/ja-jp/azure/cloud-shell/vnet/overview

## 構成図
以下のような構成で Cloud Shell から SSH で Azure Linux VM にログインできるかを試します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/0cae41cd-5305-b284-45c5-48e4eb4be795.png)


## 留意点

- ストレージと Azure Relay の料金がかかる (Cloud Shell 自体は無料)
- VNet ピアリングや Private Endpoint を使用して接続する場合はデータ転送の料金がかかる
- コンテナーサブネット、ストレージサブネットは予想される同時セッション数を考慮してサイジングする必要がある
- セカンダリリージョンはサポートされていないため、プライマリリージョンを使う必要がある (日本の VNet にアクセスしたい場合は Vnet peering を使えばアクセス可能です)
Central India
East US
North Europe
South Central US
Southeast Asia
West Europe
West US

https://learn.microsoft.com/ja-jp/samples/azure/azure-quickstart-templates/cloud-shell-vnet-storage/

:::note warn
Secondary storage regions are currently not supported in Cloud Shell VNET scenarios.
:::

## 構築手順
以下を参照して構築してきます。テンプレートの中で RBAC の割り当てもあるため、**所有者権限**での実施が必要となります。仮想ネットワークの各サブネットは事前に作るとエラーとなるため、適当なサブネットを一つ作り、あとはテンプレートでデプロイしていきます

https://learn.microsoft.com/ja-jp/azure/cloud-shell/vnet/deployment

Cloud Shell 上のデータの永続化が不要である場合は以下の手順の実施は不要です。

**4.ARM テンプレートを使用して仮想ネットワーク ストレージを作成する**

## ストレージなしでのアクセス (エフェメラルセッション)
Cloud Shell ではストレージアカウントを利用しない使い方 (エフェメラルセッション) ができるようになっています。Cloud Shell 上のデータの永続化はありません。

https://learn.microsoft.com/ja-jp/azure/cloud-shell/get-started/ephemeral?tabs=azurecli

Azure Portal にログインし、Cloud Shell を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/efd4b865-da77-b3a3-f26a-16fa156afd0d.png)

Bash (Azure CLI), PowerShell (Azure Powershell) を選びます。(このブログでは Bash を利用)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/9b54cf90-8cee-a037-9c15-7de2212539d5.png)

**"ストレージアカウントは不要です"** を選びます。
**"サブスクリプション"** は接続するリソースがあるサブスクリプションを選びます。
**"既存のプライベート仮想ネットワークを使用する"** を選びます。(チェックをしなければ通常の Cloudshell と同様、パブリックのエンドポイントを利用します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/464a0919-d68f-3558-c738-75828542c780.png)

"サブスクリプション"、"リソースグループ"、"仮想ネットワーク"、"ネットワークプロファイル"、"リレー名前空間" に先ほど作成した各リソースを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/c7388387-dda5-a420-3616-03ebab279561.png)

### 接続確認
初回アクセスはすこし時間がかかりますが、次回からは即時にアクセスできます。
Cloudshell の IP アドレスを見てみるとコンテナー用に用意したサブネットが利用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/6e81dd6b-d260-2fcc-9631-7dc00926fb0a.png)

SSH で Linux VM にログインすることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/4df1f5c4-31b9-ce1c-2f53-431ea3490d28.png)

ためしにブラウザを閉じてすぐに再接続してみましたが、作成したデータは残ってまいた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/556b5c0a-0d3d-de65-9b7d-ba18610a7996.png)

再起動 (Restart) したところデータは消えていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/6d44ef83-f5d0-675c-33a3-2455201e504c.png)


## ストレージありでアクセス
**"ストレージアカウントをマウントする"** を選択し、その他は先ほどと同様で **"適用"** を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/3d76960d-e4a4-b67a-a8bb-1ff4ebfb364c.png)

テンプレートで作成した各リソースを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/712049e1-fdf1-c2ba-5b7f-69601f07ad5a.png)

初回アクセスはすこし数分程度がかかりますが、次回からは即時にアクセスできます。
(確証はないのですが、Cloud Shell をアクティブウィンドウにしておかないと接続できないケースがありました)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/4356147b-f01f-edda-5138-8d10f408fb35.png)

試しにセッションを再起動してみましたが、データは保存されたままでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/9be4a151-78f6-91b6-c3bf-f75c7bcb2d4a.png)


## 権限管理
仮想ネットワークへアクセスできるようになるため、VM へのアクセス制御を考える必要もあります。
Cloudshell 用のリソースグループまたは各リソース (仮想ネットワーク等) の読み取り権限がなければ利用できないため、**必要なユーザーにリソースグループの閲覧者権限を割り当てる** のがよさそうです。
また、ストレージを利用する場合は Cloud Shell 利用ユーザーのストレージレベルで共同作成者以上の権限も必要になります。

https://learn.microsoft.com/ja-jp/azure/cloud-shell/persisting-shell-storage#securing-storage-access

:::note warn
セキュリティのために、各ユーザーが自分のストレージ アカウントを作成する必要があります。 Azure ロールベースのアクセス制御 (RBAC) では、ユーザーはストレージ アカウント レベルで共同作成者以上のアクセス権を持つ必要があります。
:::

## Hub＆Spoke 構成での利用
以下のような構成で UDR をコンテナーサブネット (cloudshellsubnet) に適用し、BLOB にアクセスしてみましたが問題なくアクセスできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/f934db48-8170-8343-b7ab-cd3c73223cd0.png)

## Private Endpoint 化
テンプレートで作成された Cloud Shell 用のストレージはサービスエンドポイント経由となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/fd027d6d-9db9-2259-89ac-5ed36b5f6f9c.png)

通常のストレージの手順でサブリソースで **file** を選んで、プライベートエンドと Private DNS Zone を Cloud Shell 用の仮想ネットワークに作成すれば利用できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/d857e0cd-b15e-dd8d-006e-977799e7a5b4.png)

https://learn.microsoft.com/ja-jp/azure/storage/files/storage-files-networking-endpoints?tabs=azure-portal

## NSG や Azure Firewall の利用

試しにコンテナーサブネット (cloudshellsubnet) の NSG の送信規則で VM への通信を拒否してみましたが、期待通り、拒否されました。
UDR も利用できるため、NSG, Azure Firewall での通信制御は可能なようです。