[AWS][VPC]エンドポイントとエンドポイントサービスってなにが違うの？

## 概要
AWSのマネジメントコンソールを見ていて、赤枠のサービスの違いがよくわからなかったので調べてみました。
![cap1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/2f9fd5e4-4292-8264-9ed6-59612558add5.png)

補足・誤りがありましたら、ご指摘お願いいたします。

## 記事の構成
 - [準備]ネットワーク構成
 - そもそもVPCエンドポイントってなに？
 - エンドポイントとエンドポイントサービスの違いってなに？

## [準備]ネットワーク構成
簡易ですが、以下ネットワーク・サーバを構築しております。
![nw](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/5113d2ce-8bb6-80a9-c918-98f600c4489f.png)

 - 基本的に疎通確認にはVPC_Aを使います。
VPC_Bは後でエンドポイントサービスを検証する際に使用します。
 - VPC_AのPrivate Subnetから通信する際、NAT-GWは今回必要ないので用意していません。
 - VPC_AのPublic SubnetのEC2インスタンスは以下2つの目的で作成しました。
   - Private SubnetにSSHで接続するための踏み台
   - IGW経由での疎通確認用(エンドポイント経由の通信と比較する用)

## そもそもVPCエンドポイントってなに？
### どんなサービス？
VPCにエンドポイントを作成し、そのエンドポイントを経由して他のAWSサービスや後述するエンドポイントサービスに接続することができます。

以下記事がよくまとまっており、イメージしやすいです。
 - https://jpn.nec.com/clusterpro/blog/20180115.html#anc-vpcendpoint

このVPCエンドポイントは以下の種類があります。
 - ゲートウェイ型
 - インターフェース型

いきなりゲートウェイ型やインターフェース型があるといってもイメージしにくいと思うので、まずはこれらの違いを実機を使って確認しようと思います。

### ゲートウェイ型
ゲートウェイ型の説明は公式ドキュメントがわかりやすいです。
 - https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/gateway-endpoints.html

簡単にまとめると、【S3もしくはDynamoDB】へのトラフィックはゲートウェイ型エンドポイントへルーティングされ、ゲートウェイを経由してS3やDynamoDBと通信できます。

*TIPS: 2024.3.11時点でも、ゲートウェイ型エンドポイントをサポートしているサービスはS3とDynamoDBだけでした。*

この時、ルーティングテーブルにゲートウェイ型エンドポイントを経由するルート設定を追加する必要があるようです。

具体的に実機で試してみたいと思います。

まずはPublic SubnetのEC2インスタンスからS3への通信を試してみました。
*TIPS: 事前にEC2からS3へアクセスできるようロールの設定を行っております。*

Public SubnetへはIGWがアタッチされているので、当然通信に成功します。
```
[ec2-user@ip-10-0-86-71 ~]$ # unkoはバケット名と思ってください
[ec2-user@ip-10-0-86-71 ~]$ aws s3 ls s3://unko/test.txt

2024-02-25 07:55:03          0 test.txt
```

一方NAT-GWがないのでPrivate Subnetからは通信がうまく行えません。
```
[ec2-user@ip-10-0-228-146 ~]$ aws s3 ls s3://unko/test.txt
^C() # 何も返ってこない
```
tracerouteを打ったのですが、timeoutし続けているようです。
```
[ec2-user@ip-10-0-228-146 ~]$ sudo traceroute -T -p 80 s3.ap-northeast-1.amazonaws.com
traceroute to s3.ap-northeast-1.amazonaws.com (52.xxx.xxx.xxx), 30 hops max, 60 byte packets
 1  * * *
 2  * * *
 3  * * *
 4  * * *
 5  * * *
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
14  * * *
15  * * *
(略)
```

ここでゲートウェイ型エンドポイントを用意し、もう一度疎通確認をしたいと思います。

S3はゲートウェイ型とインターフェース型の両方選択できます。
今回はゲートウェイ型を選択します。
![gw-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/6cc5a4be-c550-b979-2d1c-970a3da41a4e.png)
![gw-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/3ceb3203-1eae-6933-f096-b34908a2a8f6.png)

ゲートウェイ型を選択すると、以下のようにルートテーブルを選択する必要があるようです。
Private用のルートテーブルを選択して作成します。
![gw-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/02926ef6-fd4b-11e0-6f1a-4999b93697df.png)

これでゲートウェイ型エンドポイントの作成とルートテーブルへの追加が完了しました。

ルートテーブルを見てみると、
 - 送信先: S3
 - ターゲット: エンドポイント(vpceから始まっているもの)

　のルートが登録されています。
![gw-4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/a470dc42-38f2-938a-fbaf-dfd2a1bd4e0c.png)

*TIPS: 送信先: S3と記載しましたが、少し違和感があるかもしれません。pl-xxxxxxというよくわからないものが登録されているためです。これはマネージドプレフィックスというIPアドレス範囲のセットをルートテーブル等から使いやすくするために用意されたリストです。pl-61a54008は東京リージョンのS3に使用されるIPアドレスをまとめたものです。*

この状態でもう一度疎通を試みたいと思います。
```
[ec2-user@ip-10-0-228-146 ~]$ aws s3 ls s3://unko/test.txt
2024-02-25 07:55:03          0 test.txt
```
接続することができました。
作成したゲートウェイを通っているか確認したいのでtracerouteを打ってみたいと思います。

```
[ec2-user@ip-10-0-228-146 ~]$ sudo traceroute -T -p 80 s3.ap-northeast-1.amazonaws.com
traceroute to s3.ap-northeast-1.amazonaws.com (52.xxx.xx.xxx), 30 hops max, 60 byte packets
 1  * * *
 2  * * *
 3  * * *
 4  * * *
 5  * * *
 6  * * *
 7  * * *
 8  s3-ap-northeast-1.amazonaws.com (52.xxx.xx.xxx)  0.248 ms  0.233 ms  0.218 ms
```

ちゃんとゲートウェイを通っているようです。
*TIPS: 途中の経路がよくわかりませんが、このログはゲートウェイを通っていると判断できるものなのでしょうか？気になる方は[リンク](https://repost.aws/ja/knowledge-center/vpc-check-traffic-flow)をご参照ください*

ゲートウェイ型エンドポイントの動作確認を終わります。
ポイントは
 - ルートテーブルに、ゲートウェイとして作成したエンドポイントを登録する必要がある
 - ゲートウェイを通ってグローバルIPを持つS3と通信する
 
 ところだと思います。

### インターフェース型
インターフェース型も公式ドキュメントがわかりやすいです。
 - https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/create-interface-endpoint.html

インターフェイス型の場合、Private Subnet内にSubnet用のプライベートIPを割り当てられたエンドポイントを作ります。
そのエンドポイントを介してPrivateLinkによって対象のサービスへ接続します。

何となくイメージできなくもない気がしますが、実際に実機で検証したいと思います。

インターフェース型は様々なサービスが利用できますが、せっかくなのでゲートウェイ型との対比がしやすいようにS3を使用することにします。

![if-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/43b090b8-29f5-308e-adcc-7a255c46aecd.png)
![if-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/dcf06909-d893-5557-c40c-3ae2ffbd1699.png)

VPCとサブネットを選択します。
![if-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/a06d08ba-79bd-cbcf-5d82-3ab59d495388.png)

ルートテーブルではなくエンドポイントにアタッチするセキュリティグループの選択を求められました。

今回の要件として、Private Subnet上のEC2インスタンスからHTTPS接続が生じるためそれを許可したセキュリティグループを作成しアタッチしました。
![if-4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/d14974f8-742e-9367-d002-51da63453542.png)

作成が完了しました。

以下のようなコマンドを実行します。
```
[ec2-user@ip-10-0-228-146 ~]$ aws s3 ls --region ap-northeast-1 --endpoint-url https://bucket.vpce-xxxxxxxxxxxxxx-xxxxxxxxxxxx.s3.ap-northeast-1.vpce.amazonaws.com s3://unko/test.txt
2024-02-25 07:55:03          0 test.txt
```
ちゃんと接続できているようです。

*TIPS: 疎通確認に失敗する場合インターフェイス型エンドポイントのセキュリティグループ設定が問題の可能性があります。<br>コマンドの通り、Private SubnetにおけるEC2インスタンスからのHTTPS接続が許可されている必要があります。*
*TIPS: インターフェイス型は通信量に応じて課金が生じるので注意。具体的なコストは[公式](https://aws.amazon.com/jp/privatelink/pricing/#Interface_Endpoint_pricing)を参照*

ちなみに作成したインターフェイスを対象にnslookupコマンドを打ってみると、プライベートIPが返されています。
```
[ec2-user@ip-10-0-228-146 ~]$ nslookup vpce-xxxxxxxxxxxxx-xxxxxxxx.s3.ap-northeast-1.vpce.amazonaws.com
Server:		10.0.0.2
Address:	10.0.0.2#53

Non-authoritative answer:
Name:	vpce-xxxxxxxxxxxxx-xxxxxxxx.s3.ap-northeast-1.vpce.amazonaws.com
Address: 10.0.221.234
```
Private Subnetは10.0.128.0/17なので、ちゃんとSubnet内に存在しています。

インターフェイス型エンドポイントの動作確認を終わります。
ポイントは
 - セキュリティグループをアタッチできる
 - プライベートIPを割り振られたネットワークインターフェースを持つ
 - PrivateLinkを使用する

ところだと思います。

### まとめ
ゲートウェイ型とインターフェース型のエンドポイントを見てきました。

ゲートウェイ型は普段ネットワークに関する業務に携わっている方の場合とっつきやすいと思います。
文字通り対象のサービスへ接続するためのゲートウェイを作り、ルートテーブルでトラフィックを制御します。

一方インターフェース型は実機で試してみても、機能としては何となく理解できましたが内部でPrivateLinkを使用している以上トラフィックがL2あたりまでしかイメージできません。(≒L2までしか意識する必要がありません)
ルートテーブルを設定しなくても、エンドポイントを指定すれば裏側でうまいことPrivateLinkを使用して通信してくれます。

## エンドポイントとエンドポイントサービスの違いってなに？
ここで本題であるエンドポイントとエンドポイントサービスの違いについて触れます。
これまでの検証を通してエンドポイントについては何となく理解できたかと思います。

今回Private SubnetにはNAT-GWを用意しませんでしたが、
それでも外部にある他のサービス(今回はS3)と通信することができました。

いわばエンドポイントとはサービスを利用する側、つまり**コンシューマー**のためのサービスとも換言できます。

一方エンドポイントサービスとはサービスを提供する側、つまり**プロバイダー**側のためのサービスです。

エンドポイントは外部サービスにアクセスするために使用するのに対し、
エンドポイントサービスは外部からアクセスさせるために使用します。

[PrivateLinkの概念に関する公式ドキュメント](https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/concepts.html)のアーキテクチャ図がこの関係をわかりやすく示しています。

これで今回検証用にVPC_Bを用意した理由もよりクリアになったかと思います。

もう一度ネットワーク構成図を再掲します。
![nw](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/5113d2ce-8bb6-80a9-c918-98f600c4489f.png)

VPC_Bにはサービスを提供するためのEC2インスタンスを設置し、エンドポイントサービス経由でサービスにアクセスさせます。
※サービスといっても、単にNginxのServiceを起動しているだけです。

ちなみにPublic Subnetを作成しそこにEC2インスタンスを置いている理由は、Privase SubnetのEC2インスタンスに接続しNginxをインストールするための踏み台が欲しかったためです。

*TIPS:
今回用意したネットワーク構成図にはNAT-GWが登場しません。しかし、VPC_B上のPrivate SubnetにおけるEC2インスタンスにNginxをインストールすることができました。
通常yumやdnf等でパッケージのインストールをしたい場合はNAT-GWを経由するのが一般的な構成である認識です。
どのようにしてVPC_BにNginxをインストールしたのでしょうか。
答えは、VPC_BのPrivate Subnet用にS3へのゲートウェイ型VPCエンドポイントを用意し、VPCエンドポイント経由でインストールしました。
といっても文字だけではあまりピンとこないと思います。
気になる方は[Link](https://dev.classmethod.jp/articles/yum-update-in-private-subnet/)先が参考になります*

では実機で試したいと思います。

### 実機検証

### [準備]ロードバランサーの作成
エンドポイントサービスの使用には
 - Network Load Balancer
 - Gateway Load Balancer

のどちらかが必要なので、まずはそれを作成します。
今回はNetwork Load Balancerを作りました。
サラッとキャプチャだけ貼付しておきます。

![lb-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/b2fd2b16-ad30-a79e-dc8d-f68a39f8a131.png)
![lb-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/956a52d8-2c2e-1b69-bb9a-2e3fbbe7b173.png)
![lb-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/ce378659-34a0-eef8-8a2a-7fda651bbc43.png)
![lb-4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/fab1e880-7b6d-8295-9a4f-7cfa6109c145.png)
![lb-5](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/717e0d62-703a-d1fa-c6f3-2528de00c2fb.png)

### エンドポイントサービスの作成
次にエンドポイントサービスを作成します。
![es-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/d6c808bf-21dd-64c4-9186-6d801c6ab77a.png)
![es-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/76607edf-2d56-08a1-d42f-02a019a3b397.png)

先ほど作成したロードバランサーを選択します。

![es-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/744f3f0d-6edb-ac16-4a5d-d4c2a65fc703.png)

このエンドポイントサービスへは承諾したエンドポイントのみがアクセスできるようにします。
![es-4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/b872954c-6201-f634-0e8e-97450ef3b183.png)

これ以外に特別設定したことはありません。
この内容で作成します。

### エンドポイントの作成
先ほど作成したエンドポイントサービスを利用するためのエンドポイントを作成します。
そのためには作成したエンドポイントサービスのサービス名が必要です。
具体的には、以下赤枠の内容です。
![ep-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/428eaca0-f932-9304-0457-63e48744a4bb.png)

先ほどのエンドポイントサービスのサービス名をコピペします。
「サービス名が検証されました。」と出ればOKです。
![ep-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/f3fd5d96-f510-9cde-7f1f-ec79f5895e1f.png)

VPC_AのPrivate Subnetとセキュリティグループを選択し、作成します。

![ep-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/bcbc92ca-23ac-dd80-0d47-54dd51082262.png)
![ep-4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/5ef3e8e9-7102-46ce-d33e-63861e5070e1.png)

### エンドポイントの承諾
作成したエンドポイントについて、現在「承諾の保留中」となっています。
![ac-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/3b881e33-52f1-052d-7078-5163dcc72ef0.png)

そのためエンドポイントサービスから承諾を行う必要があります。
と言ってもやることはあまりなく、エンドポイントサービス側に来ている以下のようなリクエストに対し承諾を押下すればよいだけです。
![ac-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/fb6a1568-2a8b-bedc-65c2-5be43f54672d.png)

![ac-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715905/86c9ae93-27f5-975b-beee-ea04bf1b8334.png)

これで準備が全て整いました。

### 疎通確認
VPC_AのPrivate Subnet上のEC2からエンドポイントへ向けてcurlコマンドを実行してみます。
```
[ec2-user@ip-10-0-228-146 ~]$ curl -v vpce-xxxxxxxxxxxxxxxxxx-xxxxxxxxxx-ap-northeast-1a.vpce-svc-xxxxxxxxxxxxxxxxx.ap-northeast-1.vpce.amazonaws.com
* Host vpce-xxxxxxxxxxxxxxxxxx-xxxxxxxxxx-ap-northeast-1a.vpce-svc-xxxxxxxxxxxxxxxxx.ap-northeast-1.vpce.amazonaws.com:80 was resolved.
* IPv6: (none)
* IPv4: 10.0.224.217
*   Trying 10.0.224.217:80...
* Connected to vpce-xxxxxxxxxxxxxxxxxx-xxxxxxxxxx-ap-northeast-1a.vpce-svc-xxxxxxxxxxxxxxxxx.ap-northeast-1.vpce.amazonaws.com (10.0.224.217) port 80
> GET / HTTP/1.1
> Host: vpce-xxxxxxxxxxxxxxxxxx-xxxxxxxxxx-ap-northeast-1a.vpce-svc-xxxxxxxxxxxxxxxxx.ap-northeast-1.vpce.amazonaws.com
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.24.0
< Date: Sun, 03 Mar 2024 11:01:42 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Fri, 13 Oct 2023 13:33:26 GMT
< Connection: keep-alive
< ETag: "65294726-267"
< Accept-Ranges: bytes
< 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
* Connection #0 to host vpce-xxxxxxxxxxxxxxxxxx-xxxxxxxxxx-ap-northeast-1a.vpce-svc-xxxxxxxxxxxxxxxxx.ap-northeast-1.vpce.amazonaws.com left intact
```

ちゃんとサービスにアクセスできました。

## 最後に
最初はエンドポイントとエンドポイントサービスについて何が違うのかわかりませんでしたが、検証を通じて各々どういうサービスか理解できました。

普段僕が目にするAPIはインターネット経由でアクセスされるものが多いです。

しかしセキュリティ要件が厳しい、AWSのPrivateLinkを経由したアクセスが必要な場合は今回検証したエンドポイントサービスの使用も検討に値すると思いました。