Elastic Cloud の Private Link を使って Azure の環境と接続してみる

# Private Link とは？

:::note warn
今回は Azure の Private Link について書いています（AWS にも同名のサービスがあるので念の為）。基礎的な Azure の知識がある前提で記事を書いています。

* 2024年2月13日 - Fleet Server に関する Private Link 関連の設定を追記しました。
:::

Private Link を使うと Azure 上で動いているリソースから、Azure の PaaS サービスやサードパーティーが Azure 上で提供するサービスへの通信を、 Azure のネットワーク内（Microsoft のバックボーン）で完結させる事ができるようになります。


:::note info
- Elastic Cloud に Azure の Private Link がリリースされた際の、[[ブログ記事]](https://www.elastic.co/blog/secure-your-deployments-on-elastic-cloud-with-azure-private-link)
- Azure Private Link の正確な情報・最新情報に関しては、[[Azure のドキュメント]](https://docs.microsoft.com/ja-jp/azure/private-link/private-link-overview) をご参照ください
:::

Elastic Cloud でクラスターを作成すると、パブリックなエンドポイントが割り振られ、インターネット経由でアクセスする事になります。しかし、セキュリティ要件やユースケース次第で、インターネット経由の通信を避けたい場合もあります。

Private Link はそのようなユーザーのために、Azure のリソースと Elastic Cloud を Azure のネットワーク内での通信を可能にします。





# Private Link の構成

Elastic Cloud で Private Link を設定すると、下記のような構成になります。

![blog-azure-private-link-diagram.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/1630b112-64bf-11cc-88d1-63f04c52cb75.jpeg)

[[https://www.elastic.co/blog/secure-your-deployments-on-elastic-cloud-with-azure-private-link] より引用](https://www.elastic.co/blog/secure-your-deployments-on-elastic-cloud-with-azure-private-link) 

Azure の VM は、自分で管理する VNet (Customer VNet) 内にデプロイされているとします。
Elastic Cloud は Elastic が管理する VNet (Elastic VNet) 内にて管理されています。

Customer VNet から Elastic VNet への接続を可能にするため、Customer VNet 内に Elastic VNet を接続するために設定された *Private Link Service*、 *Private Endpoint*、*Private DNS Zone* が必要となります。





# 環境の作成

:::note warn
作成には Azure のサブスクリプションと Elastic Cloud のアカウントが必要です。ある程度 Azure を触っている想定で書いているため、作成手順を一部割愛しておりますので、必要あれば Azure のドキュメント等もご参照ください。
:::

### 1) [Elastic] デプロイメントの作成

まずは Elastic Cloud でクラスターをデプロイします。今回は Azure Private Link を利用するので Cloud Provider は Azure を指定します。Private Link とデプロイメントは同一の地域（region）を選択する必要があります。

![Create Deployment](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/0b0a3c86-c3a5-baed-cb1c-0d2e53b6a6d7.png)

一度しか表示されないので、忘れずに BASIC 認証用にパスワードをメモしておきましょう。

![Account Password](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/2cd04da3-4e53-817d-6fcb-2b8e9ebbc0ce.png)

### 2) [Azure] リソースグループの作成

任意の名前と地域にリソースグループを作成します。一部 Azure のリソースがリソースグループの地域に紐づくため、必須ではないですが基本的には Elastic Cloud と同一の地域を利用するのが安心です。

### 3) [Azure] Virtual Network の準備

Private Link で接続するためには、VNet が必要になります。この VNet 内に、Private Endpoint や DNS を紐付けて、最終的には Private Link の向き先として設定します。既存の VNet を利用する場合は、改めて作成する必要はありません。

### 4) [Azure] Private Endpoint の作成

Private Endpoint のリソースを作成します。ドキュメント内にある情報は必須となります[[ドキュメント]](https://www.elastic.co/guide/en/cloud/current/ec-traffic-filtering-vnet.html)。
今回リリースする地域に該当する *Azure Private Link Service Alias* の値と *Private hosted zone domain name* の２つが必要になるのでメモしておきます。（下記の値は 2022年5月時点のドキュメントの japaneast の値）
- *Azure Private Link Service Alias*: `japaneast-prod-006-privatelink-service.cfcf2172-917a-4260-b002-3e7183e56fd0.japaneast.azure.privatelinkservice`
- *Private hosted zone domain name*: `privatelink.japaneast.azure.elastic-cloud.com`

Azure で Private Endpoint を実際に作成していきます。

- Azure ポータルから *Private Endpoint* を検索し、リソースの作成に進みます。
    - 名前、地域は任意の物を記入します
    - *リソース ID またはエイリアスを使って Azure リソースに接続します*　を選択し、`リソース ID またはエイリアス`に *Azure Private Link Service Alias* の値を入力します (japaneast でいうと `japaneast-prod-006-privatelink-service.cfcf2172-917a-4260-b002-3e7183e56fd0.japaneast.azure.privatelinkservice`)
    - Private Endpoint を立てたい VNet を選択します。もしリストに VNet が表示されない場合、地域の選択が間違っている等が考えられます
    - Private Endpoint を作成します

### 5) [Azure] プライベート DNS ゾーンの作成と VNet への紐付け

Elastic Cloud はプライベート DNS ゾーンを使ってホスト名の解決を行っています。

- Azure ポータルから *Private DNS Zone* を検索し、リソースの作成に進みます。
    - 名前は、地域に該当する *Private hosted zone domain name* の値を入力します（`privatelink.japaneast.azure.elastic-cloud.com`）
    - プライベート DNS ゾーンを作成します
- 作成が完了したら、VNet に紐付ける必要があります。そうする事で、ホスト名を使ってクラスターにアクセスできるようになります。
    - 作成したプライベート DNS ゾーンのリソースにアクセスします
    - 左のメニューから**仮想ネットワークリンク**をクリックします
    - 一覧の上の **追加** をクリックし、プライベートエンドポイントを作成した VNet を指定し、作成します。

### 6) [Azure] DNS レコードの作成

DNS ゾーンを作成したのはいいですが、ホスト名をプライベートエンドポイントに解決できるよう、DNS レコードを作成します。

- まずは、プライベートエンドポイントのプライベートIPが必要になります
    - 先程作成したプライベートエンドポイントのリソースにアクセスします
    - 左のメニューから、**DNS の構成**にアクセスし、紐付いたNICのプライベートIPをメモしておきます。（もし紐付いているNICがわかっていれば、そちらから直接確認しても問題ありません。プライベートIPがわかれば手段は問いません）
- DNS レコードの作成に進みます
    - 先程作成したプライベート DNS ゾーンのリソースにアクセスします
    - 概要画面の上部の **+ レコードセット** をクリックします
    - 下記の画像のようなフォームが表示されるので、記入、作成します
        - *名前*: *
        - *種類*: A
        - *IP アドレス*: [先程メモしたプライベートIP]
        - それ以外は任意
![Screen_Shot_2022-05-25_at_12_13_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/1dcdb127-6460-b231-4ac6-dcb5d579f83d.png)

Azure で必要な作業は以上となりますが、もう少しだけ Azure ポータルは使うので、まだ画面を閉じないでください。

### 7) [Elastic] トラフィックフィルターの作成

Elastic Cloud のポータルから、Private Link を作成します。作成に必要な Azure の情報があるので、それをまず取りに行きます。

- 先程作成したプライベートエンドポイントのリソースにアクセスします。
    - 概要画面の右上にある **JSONビュー** をクリックします
    - 長い JSON が表示されるうちから、下記の２項目をメモします。
        - `name`
        - `properties.resourceGuid` 
![Screen_Shot_2022-05-23_at_17_40_47-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/646eba70-2c4f-ba05-bcbf-8cd577580774.png)

- Elastic Cloud のポータルにアクセスします。デプロイメント一覧の右側にある歯車アイコンをクリックし、デプロイメントの編集画面にアクセスします。
![Screen_Shot_2022-05-26_at_12_09_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/fa506353-0dfe-9ad0-ce70-998247f932e9.png)

- 左側にある **Features** をクリックします
- **Add traffic filters** をクリックします
![Screen_Shot_2022-05-25_at_11_33_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/ab2e95ba-d7a8-4d10-e6d9-1d9bba61a612.png)

- 画面右側にある、 **Create filter** をクリックし、フォームを開きます。
- 下記のように入力し、作成します
    - *Cloud Provider*: Azure
    - *Region*: Tokyo(japaneast) ＊あるいはプライベートエンドポイントに選択した地域
    - *Resource name*: プライベートエンドポイントリソースの `name` 
    - *Resource ID*: プライベートエンドポイントリソースの `properties.resourceGuid`
    - それ以外は任意 
![Screen_Shot_2022-05-25_at_11_39_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/9ac0372c-bd4b-f870-420f-c77519f9bc04.png)

### 8) [Elastic] トラフィックフィルターの紐付け

トラフィックフィルターを作成できたので、次はフィルターをデプロイメントに紐付けます。

- 改めてElastic Cloud のポータルにアクセスします。デプロイメント一覧の右側にある歯車アイコンをクリックし、デプロイメントの編集画面にアクセスします。
- 画面左側のメニューにある、**Security** をクリックします
- **Traffic filters* の下にある **Apply filter** をクリックします


![Screen_Shot_2022-05-25_at_11_57_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/da76ddff-8433-c0b5-c6be-f205169857f3.png)

- トラフィックフィルターを選択するパネルが表示されるので、先程作成したトラフィックフィルターを選択し、*Apply filter*をクリックします。もし表示されない場合は、デプロイメントとトラフィックフィルターのクラウドプラットフォームや、地域が異なる場合があるので確認が必要となります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/1dec5c27-dad4-6416-21e6-84f294cb6e30.png" width="400">

以上で Private Link の設定完了です。






# Private Link で接続してみる

環境の設定が出来たので、今後はアクセスして、正しく接続できる事を確認しましょう。

当然、VNet 内からしかアクセス出来ないので、VNet に接続した Azure のリソースが存在する前提で話します。ない場合は別途作成する必要があります。

Private Link 経由でデプロイメントにアクセスする場合、 Elastic Cloud で用意されるパブリックエンドポイントは利用出来なくなります。Private Link で使うホスト名はデプロイメントで定義されている `Cluster ID` と作成した DNS ゾーンから組みてる事が出来ます。

まずアクセスしたいリソースの `Cluster ID` を取得します。`Cluster ID`はデプロイメントの管理画面から取得できます。各リソースの種類毎に（Elasticsearch, Kibana, 等）`Cluster ID` を持っています。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/736acd7e-fc4d-5117-c837-7091d95176c2.png)

ホスト名は下記の通りとなります。

```
# Private Link のホスト名
https://{Cluster ID}.{プライベートDNSゾーンで指定したホスト名}:9243/
```

例えば、今回作ったデプロイメントのElasticsearch の Cluster ID が `aaabbbccc000111222333` だとすると
```
https://aaabbbccc000111222333.privatelink.japaneast.azure.elastic-cloud.com:9243
```
となります。


### 接続が可能な環境からの接続

```sh
# 許可した VNet からのアクセス。 Basic 認証でアクセスしていますので、password はデプロイメントを作成したときに表示されていた物を利用します。
$ curl -u elastic:password https://aaabbbccc000111222333.privatelink.japaneast.azure.elastic-cloud.com:9243
> {
  "name" : "instance-0000000000",
  "cluster_name" : "eae080c958b24866ae8c2a1a02bbb33d",
  "cluster_uuid" : "yBrE9sLXTiy-mYiW6e9OXQ",
  "version" : {
    "number" : "8.2.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "b174af62e8dd9f4ac4d25875e9381ffe2b9282c5",
    "build_date" : "2022-04-20T10:35:10.180408517Z",
    "build_snapshot" : false,
    "lucene_version" : "9.1.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

# 当然、APIも叩けます
$ curl -u elastic:password https://aaabbbccc000111222333.privatelink.japaneast.azure.elastic-cloud.com:9243/_search/
{"took":0,"timed_out":false,"_shards":{"total":0,"successful":0,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":0.0,"hits":[]}}
```

### 接続できない環境からの接続

FYI程度にですが、Traffic Filter を使ったとき、パブリックエンドポイントがどのような挙動をするかの簡単な実験です。ホスト名の構造も Private Link のホスト名と全然違います。

```sh
# そもそも存在しないパブリックエンドポイントにアクセスした場合
$ curl https://non-existent-cluster-hogehoge.kb.japaneast.azure.elastic-cloud.com:9243/api/security/saml/callback
> {"ok":false,"message":"Unknown resource."}
```

```sh
# Private Link を設定した時に、パブリックエンドポイントにアクセスした場合
$ curl https://privatelinkdemo.kb.japaneast.azure.elastic-cloud.com:9243/api/security/saml/callback
> {"ok":false,"message":"Forbidden"}
```

上記でわかるように、パブリックエンドポイントの存在を隠蔽するものではなく、あくまでもアクセスを制御するものだとわかります。


# サンプルスクリプト

既存のESSクラスターに Azure Private Link を設定するためのAzure ARM テンプレートとシェルスクリプトをシェアします。
個人的に試すために作成したスクリプトですので、参考程度でお考えください。
私個人の環境では 2022年5月に実行出来ていますが、細かい環境情報は余力があれば後日書きます。（すいません、放置の可能性大です）

https://github.com/tjws052009/ess-azure-private-link

---
### <2024年2月13日追記>

# Fleet Server の接続設定

Private Link で Fleet Server を使うためには URL の設定が必要となります。デフォルトのパブリックの URL を Private link のエンドポイントに切り替える必要があります。

Kibana にログインし、画面上部の検索バーから **Fleet settings** を検索し、 **Fleet / Settings** をクリックします。

\# 左のナビゲーションバーを開き、メニューから **Fleet** をクリックし、遷移した先の上部タブから **Settings** をクリックする事で同じページに飛ぶ事ができます。

![Fleet Settings search](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/65cec2f4-115f-16ac-dc52-121231ee7067.png)

Fleet の設定ページで、下記の2箇所に変更を加えます。

- `Fleet server hosts`
- `Outputs`

\# 複数設定を用意したい場合は、設定を新規作成し、Fleetサーバーやエージェントを設定する際に適切に選択する必要があります。

![Fleet Settings page](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/56d3c346-c20b-5455-3245-ff96a5d32a7e.png)

### Fleet server hosts

まずは `Fleet server hosts` の　`Default` の設定を更新します。
既存のURLを下記の値に更新します。Private link 経由で Fleet server にアクセスするためのURL です。

```
https://{Fleet server component ID}.{プライベートDNSゾーンで指定したホスト名}:443/
```

手順どおりに作成している場合は、`fleet` と `japaneast` の間に `privatelink` を追加するだけで大丈夫なはずです。

```
- https://ffss000111222333.fleet.japaneast.azure.elastic-cloud.com:443\+ https://ffss000111222333.fleet.privatelink.japaneast.azure.elastic-cloud.com:443
```

![Fleet server hosts settings](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599974/2ee15d7d-75dc-618f-3313-fa03bcc7c89a.png)

### Outputs

次に `Outputs` の `default` の設定を更新します。
既存のURLを下記の値に更新します。Private link 経由で Elasticserach にアクセスするためのURLです。

```
https://{Cluster ID}.{プライベートDNSゾーンで指定したホスト名}:443/
```

先程と同様、手順どおりに作成している場合は、`fleet` と `japaneast` の間に `privatelink` を追加するだけで大丈夫なはずです。

```
- https://aaabbbccc000111222333.japaneast.azure.elastic-cloud.com:9243
+ https://aaabbbccc000111222333.privatelink.japaneast.azure.elastic-cloud.com:9243
```

以上の設定を行えば、Fleet server が Private link 経由でも使えるようになるはずです。


### \</2024年2月13日追記>
---


# 注意点

Private link は一方通行の通信となるため、[自分のリソース] => [Elastic Cloud]は VNet 間で通信されますが、[Elastic Cloud] => [自分のリソース]のVNet 間通信は出来ません。

その他の制約等をまとめた [[ドキュメント]](https://www.elastic.co/guide/en/cloud/current/ec-restrictions.html) がありますので、一度ご確認いただくことをおすすめいたします。


# 最後に

手順を中心に Private Link の接続に関して書いてみましたが、これを使う事で弊社のマネージドサービスと Azure のリソース間の通信のセキュリティを強化する事が可能です。ぜひお試しください。