Azure 仮想ネットワークサービスエンドポイントと Azure Private Link の挙動確認

# はじめに
Azure の VNet 内の VM などから Azure PaaS リソース (Azure Storage、SQL Database など) に対して、Azure のバックボーンネットワーク経由で直接接続する方法として、**Azure 仮想ネットワークサービスエンドポイント** と **Azure Private Link** の 2 つがあります。

これら 2 つの方法は、似ているようで挙動に違いがあります。詳細は以下ドキュメントを確認頂くとして、本記事では両者の構成や挙動がどのように違うかをストレージアカウントを例にして簡単にまとめたいと思います。

- [Azure 仮想ネットワーク サービス エンドポイント | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/virtual-network/virtual-network-service-endpoints-overview)
- [Azure Private Link とは | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/private-link/private-link-overview)

# 追記 (2020/9/9)
サービスエンドポイントと Private Link を 1 つのリソースで併用する方法について別記事にまとめています。よろしければこちらもご覧ください。

[Azure 仮想ネットワークサービスエンドポイントと Azure Private Link の併用方法 - Qiita](https://qiita.com/nakazax/items/937a512c0b69abdbd6cf)

# 構成図
|![qiita-service-endpoint-private-link.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/42bddd79-b43c-f233-2c29-0e3c0dc33f94.png)|
|:-:|

上記のように 2 つのストレージアカウントを作成し、1 つにサービスエンドポイント、もう 1 つにPrivate Link を設定します。これらのストレージアカウント内のデータにはインターネット経由ではアクセスできず、VNet 内の VM からのみアクセスが可能です。

オプションですが、VM の SSH のポート (Port: 22) をインターネットに露出させないように、Azure ポータル -> Azure Bastion ホストを経由して VM にアクセスするようにします。

# 事前作業
事前作業として以下を実施しておきます。

1. 仮想ネットワーク (VNet) & サブネット作成
2. 仮想マシン (VM) 作成
3. Bastion ホスト作成
4. Bastion ホスト -> VM 接続確認
5. VM に Azure CLI をインストール

### VNet & サブネット作成
キャプチャの通り、VNet とサブネットを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/bd852d92-80e7-c030-1f14-886bb190ab18.png)

### VM 作成
`VMSubnet` に VM を作成します。Bastion ホスト経由でアクセスするためパブリック IP は付与していません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/ff7c82aa-6613-f977-6b7a-bd458111bdcc.png)

### Bastion ホスト作成
`AzureBastionSubnet` に Bastion ホストを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/3824557c-7fca-b08c-9b2d-48fddcd30b0b.png)

### Bastion ホスト -> VM 接続確認
VM の左側メニューの [Bastion] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/a4e5526c-ba95-c9e5-e2fc-fed9e1ca1fd5.png)

VM 作成時に指定した認証の情報 (ここではユーザー名 & パスワード) を入力して VM に接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/ee0b2980-5df6-8e40-bb25-71975699b591.png)

以下のように Web ブラウザの別タブでターミナルが起動すれば接続 OK です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/ec243b9f-a0bd-e955-e4aa-37b33f5210cd.png)

### VM に Azure CLI をインストール
この後の動作確認で使うため VM に Azure CLI をインストールします。
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-apt?view=azure-cli-latest

```
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
```

# 挙動確認 : サービスエンドポイント
それでは、サービスエンドポイントを設定したストレージアカウントの挙動を確認していきます。

### ストレージアカウント作成
ストレージアカウントの作成画面です。[基本] ページでは必要な情報を入力すれば OK です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/aebc863f-ebf8-988a-15fd-96ecd9e36b32.png)

[ネットワーク] ページで **パブリックエンドポイント (選択されたネットワーク)** にチェックし、[仮想ネットワーク] に接続を許可するサブネット (ここでは `VmSubnet`) を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/e8fa3e6b-9f9b-3dfb-da76-92c5176ad532.png)

他のページは特筆すべき点はありません。ストレージアカウントを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/da1ddef4-7ba1-0efd-7498-6a52c802e4d7.png)

ストレージアカウント作成時にサービスエンドポイントで指定した VNet を見てみると以下キャプチャのようにサービスエンドポイントが追加されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/fc6419cd-bf2d-bcf1-da4e-c96b72bb8562.png)

### 名前解決
サービスエンドポイントを設定したサブネット `VmSubnet` 内の VM からストレージアカウントの FQDN (完全修飾ドメイン名) に対して名前解決のコマンド (`nslookup`) を実行すると**パブリック IP アドレス**に解決されます。
VNet 外のコンピューター (手元の PC) でも同じくパブリック IP アドレスに解決されます。

(`VmSubnet` の VM からの名前解決 : パブリック IP アドレスに解決される)

```
$ nslookup stnakazaxblobse1.blob.core.windows.net
Server:127.0.0.53
Address:127.0.0.53#53

Non-authoritative answer:
stnakazaxblobse1.blob.core.windows.netcanonical name = blob.mwh03prdstr03a.store.core.windows.net.
Name:blob.mwh03prdstr03a.store.core.windows.net
Address: 52.239.237.100
```

(VNet 外のコンピューターからの名前解決 : パブリック IP アドレスに解決される)

```
$ nslookup stnakazaxblobse1.blob.core.windows.net
Server:         172.26.192.1
Address:        172.26.192.1#53

Non-authoritative answer:
stnakazaxblobse1.blob.core.windows.net  canonical name = blob.mwh03prdstr03a.store.core.windows.net.
Name:   blob.mwh03prdstr03a.store.core.windows.net
Address: 52.239.237.100
```

### Azure ポータルでの操作
サービスエンドポイントを設定したストレージアカウントに対して、Azure ポータルからコンテナーの作成、一覧表示、削除等の操作を行うことはできます。ただ、コンテナー内のデータを表示しようとすると権限不足のメッセージが表示されます。

(コンテナー作成 : エラー無し)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/938cccf4-791f-f2ca-da57-34b51f1c91c7.png)

(コンテナー一覧表示 : エラー無し)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/51282fd3-9a37-f5e6-f57c-18b3a15d1a2d.png)

(コンテナー内のデータを見ようとすると権限不足のメッセージが表示される)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/1240bad0-f9fe-c544-a96a-7cf99ad191d5.png)

### Azure CLI での操作
サービスエンドポイントを設定したサブネット `VmSubnet` 内の VM から、ストレージアカウントのコンテナーへのファイルアップロード、ファイルの一覧表示のコマンドは成功します。
一方、VNet 外のコンピューター (手元の PC) から同様のコマンドを実行するとエラーメッセージが出力され、失敗します。

(`VmSubnet` の VM からのファイルのアップロード : 成功)

```
$ az storage blob upload \
> --file example1.txt \
> --name example1.txt \
> --account-name stnakazaxblobse1 \
> --container-name test-container \
> --account-key xxx
Finished[#############################################################]  100.0000%
{
  "etag": "\"0x8D85029187541FC\"",
  "lastModified": "2020-09-03T16:47:50+00:00"
}
```

(`VmSubnet` の VM からのファイルの一覧表示 : 成功)

```
$ az storage blob list \
> --account-name stnakazaxblobse1 \
> --container-name test-container \
> --account-key xxx
[
  {
    "container": "test-container",
    (省略)
    "versionId": null
  }
]
```

(VNet 外のコンピューターからのファイルの一覧表示 : 失敗)

```
$ az storage blob list \
> --account-name stnakazaxblobse1 \
> --container-name test-container \
> --account-key xxx

The request may be blocked by network rules of storage account. Please check network rule set using 'az storage account show -n accountname --query networkRuleSet'.
If you want to change the default action to apply when no rule matches, please use 'az storage account update'.
```

# 挙動確認 : Private Link
次に、Private Link を設定したストレージアカウントの挙動を確認していきます。

### ストレージアカウント作成
ストレージアカウントの作成画面です。[基本ページ] では必要な情報を入力すれば OK です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/ff15a86b-9ccd-8d47-efe1-242d8a9436dd.png)

[ネットワーク] ページの [接続方法] で **プライベートエンドポイント** にチェックし [追加] をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/c5754d67-f36a-7a24-59b7-94252aca2fec.png)

プライベートエンドポイントの作成画面です。[サブネット] の下に書かれていますが、プライベートエンドポイントに対して NSG (Network Security Group) は無効であることに留意が必要です。
また、プライベートエンドポイントとプライベートに接続するには DNS レコードが必要なため、ここでは [プライベート DNS ゾーンとの統合する] で [はい] を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/907282ec-040b-754f-1e8c-f8b8b76663b1.png)

入力が正しいのにリソースグループ欄がエラーになることがありますが、一旦別のリソースグループを選択して [OK] を押して、再度目的のリソースグループに変更することで上手く行くと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/83b4e43e-0136-7aac-8663-df29e9aa1dcf.png)

後は必要な情報を入力し、ストレージアカウントを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/a7016b86-c3cb-220e-3f43-c0604d356089.png)

すると以下の赤枠で囲んだリソース (プライベート DNS ゾーン、ストレージアカウント、プライベートエンドポイント、ネットワークインターフェイス) が作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/e56f0501-e401-eb48-d577-c51332861119.png)

- ストレージアカウント > ファイアウォールと仮想ネットワーク
    - 許可するアクセス先 : 選択されたネットワークがチェックされている
    - 仮想ネットワーク : ネットワークが選択されていない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/ac8e4702-6296-cdec-42aa-25fa22cc6c23.png)

- ストレージアカウント > プライベート エンドポイント接続
    - プライベートエンドポイント接続が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/fad21b06-bb62-9172-f378-1786037f4443.png)

- ストレージアカウント > プライベート エンドポイント接続 > プライベート エンドポイント
    - 以下のようにストレージアカウントの FQDN にプライベート IP が関連付けられたカスタム DNS 設定が表示されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/56112789-0bb9-44da-5540-6529e6ebd96c.png)

- プライベート DNS ゾーン
    - ストレージアカウント名とプライベート IP が関連付けられた A レコードが存在する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284925/4531829b-9a96-e792-7c84-44cc428e8d1b.png)

### 名前解決
`VmSubnet` 内の VM からストレージアカウントの FQDN (完全修飾ドメイン名) に対して名前解決のコマンド (nslookup) を実行すると**プライベート IP アドレス**に解決されます。
VNet 外のコンピューター (手元の PC) ではパブリック IP アドレスに解決されます。

(`VmSubnet` の VM からの名前解決 : プライベート IP アドレスに解決される)

```
$ nslookup stnakazaxblobpl1.blob.core.windows.net
Server:127.0.0.53
Address:127.0.0.53#53

Non-authoritative answer:
stnakazaxblobpl1.blob.core.windows.netcanonical name = stnakazaxblobpl1.privatelink.blob.core.windows.net.
Name:stnakazaxblobpl1.privatelink.blob.core.windows.net
Address: 10.0.20.4
```

(VNet 外のコンピューターからの名前解決 : パブリック IP アドレスに解決される)

```
$ nslookup stnakazaxblobpl1.blob.core.windows.net
Server:         172.26.192.1
Address:        172.26.192.1#53

Non-authoritative answer:
stnakazaxblobpl1.blob.core.windows.net  canonical name = stnakazaxblobpl1.privatelink.blob.core.windows.net.
stnakazaxblobpl1.privatelink.blob.core.windows.net      canonical name = blob.mwh03prdstr02a.store.core.windows.net.
Name:   blob.mwh03prdstr02a.store.core.windows.net
Address: 52.239.237.36
```

### Azure ポータルでの操作
Private Link を設定したストレージアカウントに対して、Azure ポータルからコンテナーの作成、一覧表示、削除等の操作を行うことはできます。ただ、コンテナー内のデータを表示しようとすると権限不足のメッセージが表示されます。

(サービスエンドポイントとほぼ同じ内容のためキャプチャ省略)

### Azure CLI での操作
`VmSubnet` 内の VM から、ストレージアカウントのコンテナーへのファイルアップロード、ファイルの一覧表示のコマンドは成功します。
一方、VNet 外のコンピューター (手元の PC) から同様のコマンドを実行するとエラーメッセージが出力され、失敗します。

(`VmSubnet` の VM からのファイルのアップロード : 成功)

```
$ az storage blob upload \
> --file example1.txt \
> --name example1.txt \
> --account-name stnakazaxblobpl1 \
> --container-name test-container \
> --account-key xxx
Finished[#############################################################]  100.0000%
{
  "etag": "\"0x8D8502F35AAE20E\"",
  "lastModified": "2020-09-03T17:31:36+00:00"
}
```

(`VmSubnet` の VM からのファイルの一覧表示 : 成功)

```
$ az storage blob list \
> --account-name stnakazaxblobpl1 \
> --container-name test-container \
> --account-key xxx
[
  {
    "container": "test-container",
    (省略)
    "versionId": null
  }
]
```

(VNet 外のコンピューターからのファイルの一覧表示 : 失敗)

```
$ az storage blob list \
> --account-name stnakazaxblobpl1 \
> --container-name test-container \
> --account-key xxx

The request may be blocked by network rules of storage account. Please check network rule set using 'az storage account show -n accountname --query networkRuleSet'.
If you want to change the default action to apply when no rule matches, please use 'az storage account update'.
```

以上です。