VPCエンドポイントを設置したらCloud9(EC2)に繋がらない！

# はじめに
開発チーム内で検証用にAWSを使っていますが、先日、これまで使えていたCloud9のインスタンスに接続できなくなったという問い合わせを受けました。
[Cloud9がサービスの新規利用終了する話](https://aws.amazon.com/jp/blogs/devops/how-to-migrate-from-aws-cloud9-to-aws-ide-toolkits-or-aws-cloudshell/)は聞いていましたが、使用実績のあるアカウントでは引き続き使えるとも聞いていたので、接続できなくなるはずはないのに……と思いつつ原因を調べました。
調査の結果、別の原因が判明したので、教訓も兼ねて記事にまとめておきます。
このおかげで、VPCエンドポイントへの理解もより深まりました。

なお、今回のトラブルの原因はCloud9とは関係ありません。

## TL;DR
- VPCの使いまわしはやめよう
- セキュリティグループの使いまわしもやめよう
- VPCエンドポイントを設置したら、通信に影響がでないか環境構成を確認しよう

# 何が起きたのか
突然Cloud9にアクセスできなくなる前後で何か環境の変化があったのでしょうか。

## 平和だったころ
平和だった元々の環境をざっくり図に起こすとこんな感じです。
Cloud9のインスタンスはパブリックサブネットに配置されています。
Cloud9のインスタンスとローカルPC間の通信経路を赤線で示しました。
この通信は、インターネットゲートウェイ越しにインターネットを介して確立します。

![最初の構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3830637/55951309-d5a7-71fd-03f9-451d6904ed95.png)

:::note Cloud9の実態
ご存じの方も多いと思いますが、Cloud9の実態はEC2インスタンスです。
よって、普通のEC2インスタンスと同様にVPCやセキュリティグループの設定があります。
:::

## 思い当たる節
接続できなくなる前後で、何か変化がなかったか思い返してみると、別の開発者がEC2インスタンスを新しく立てるというという出来事があったことを思い出しました。
このEC2インスタンスは、デフォルトで作成されるVPCのプライベートサブネットに配置されました。
そして、セキュリティグループもデフォルトで作成されたものを割り当てていました。

![変化1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3830637/3dcf22e3-8b5f-980f-99b5-3a5f1e7261dd.png)

その後、プライベートサブネット内にあるこのEC2インスタンスにセッションマネージャーで接続したいということで、VPCエンドポイントが設置されました。
鋭い方はここでお気づきかもしれませんが、これが今回のトラブルの発端です。

:::note
セッションマネージャー接続時に設置が必要なVPCエンドポイントは、`com.amazonaws.region.ssm`と`com.amazonaws.region.ssmmessages`の2つです。
:::

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/troubleshooting-ssm-agent.html#systems-manager-ssm-agent-troubleshooting-endpoint-access

VPCエンドポイントには、EC2インスタンスと同じデフォルトのセキュリティグループを割り当てていました。
これで、めでたしめでたし、EC2インスタンスにセッションマネージャーで接続できるようになりました。
通信経路は青色で示します。

![変化2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3830637/f5d747cf-dd8d-3f23-73db-79c9a77d7361.png)

……はたして本当にこの図の通りの通信経路になるでしょうか？

## VPCエンドポイント設置後の実際の通信経路
VPCエンドポイントにはインターフェース型とゲートウェイ型の2種類があります。
今回設置したインターフェース型のVPCエンドポイントは、そのサービス宛ての通信はDNSによる名前解決でエンドポイントのIPアドレスに名前解決されるようになる仕組みとなっています。
参考情報はこちら。

https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/concepts.html

https://qiita.com/charita/items/fe94680133419a03aade

これが実は地味に強力で、接続元のインスタンスがプライベートサブネットにあろうとパブリックサブネットにあろうと、設置されたVPC内の対象サービスとの通信は吸い込まれるかのごとく強制的にVPCエンドポイント経由になります。
つまり、実際の通信経路は次の図のようになります。

![変化3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3830637/3b0f0b30-ca2a-d119-ea00-d536f33bfae9.png)

それで、ここでもう1つ思い出したいのが、セキュリティグループの設定です。
EC2インスタンスとVPCエンドポイントには、~~新しく用意するのが面倒なこともあって~~同じデフォルトのセキュリティグループを設定していました。
もちろん、同じセキュリティグループ内ではセッションマネージャーの通信が通るようにインバウンドの通信を許可していました。
一方、Cloud9用のセキュリティグループからの通信は……**ルールを追加するのを忘れていました**。

ということで、実際の通信経路は以下の図の通りです。

![実際](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3830637/8baf7367-3b6e-2625-0319-c05b607ddb67.png)

Cloud9用セキュリティグループからの通信は、デフォルトのセキュリティグループ内にアクセスしようとしたところでブロックされている状況です。
改めてみると、単純なセキュリティグループの設定許可漏れですが、いろいろな要素が絡むと真因を見つけづらいものですね。

## その後
原因が分かったところで、ひとまずデフォルトのセキュリティグループにCloud9用のセキュリティグループからのインバウンドの通信を許可するルールを追加しました。
すると、元通りCloud9のインスタンスに接続できるようになりました！
セキュリティグループに関しては、今後適切な単位で切り分けたいと思います。

# 反省点と教訓
今回のトラブルは、VPCエンドポイントを設置すると、環境にどのような変化が起きるかの理解が浅いまま変更を加えたことが原因でした。
また元を言えば、VPCやセキュリティグループを使いまわしたことも原因です。
さらに、新しく設置したリソースにセキュリティグループは同一のもの割り当てたたために、当該セキュリティグループ外からの通信に影響が出たことが露呈しづらくなっていました。

今回と同様のケースは、ネット上でも記事が見つかるので、割とありがちな失敗ですね。

https://techblog.asia-quest.jp/202407/a-story-about-an-unrecognized-vpc-endpoint-that-was-the-reason-why-session-manager-could-not-connect-to-ec2

既存の環境に影響を与えないために、これからは以下のことに気をつけて利用していこうと思います。
* 新しく環境を作る時には、VPCやセキュリティグループを適切な単位で切り分けて新しいものを用意すること
* セキュリティグループを割り当てるときは、既存のどのリソースが属しているか確認すること
* 環境に変更を加える場合は、利用者に一声かけること

本記事が皆さんのトラブル解決に繋がれば嬉しいです。