はじめに
先日の AWS re:Inforce 2023 で発表された新機能の一つとして、EC2 Instance Connect Endpoint(以下、EICエンドポイント) があります。
これは、パブリックIPアドレスを持たないEC2インスタンスにSSH接続を可能にするもので、従来踏み台サーバやSSM Session Managerを使用する必要があった環境での新たな選択肢として注目されています。
EICエンドポイントがどのようなものかについては既に多くのブログが投稿されていると思いますので、本記事では実装の際のポイントと、ちょっと試してみたい方向けのterraformコードを公開したいと思います。
ちょっと待って🖐
「EC2 Instance Connect って元々ありましたよね🤔?」
「Endpoint がついたけど何が違うんですか🤔?」
と思った方もいらっしゃるかと思います。
これはその通りで、EC2 Instance Connect は既に存在していた機能なのですがそれぞれ役割が違います。
とてもざっくり言うと、
EC2 Instance Connect
・・・ 一時的なSSH公開鍵を生成・交換することで、鍵の管理を不要にする機能
EIC Endpoint
・・・ プライベートサブネット内にあるインスタンスと通信するためのトンネルを生成する機能
といったイメージです。(詳細は各ドキュメントを参照してください。)
役割の違う機能なので、それぞれ単独で使うことも組み合わせて使うこともできます。
実装のポイント
ここからは実装の際に気を付けたいポイントをいくつか挙げていきます。
■クライアントIPの保存
EIC Endpoint 作成時の設定項目に、Preserve Client IP
があります。
これはインスタンスへの接続時に、接続元クライアントのIPアドレスを保持するかどうかの設定です。
これ自体は要件次第でどちらを選択しても良いのですが、一部インスタンスタイプに制限があります。
次のインスタンス タイプは、クライアント IP の保存をサポートしていません: C1、CC1、CC2、CG1、CG2、CR1、G1、G2、HI1、HS1、M1、M2、M3、および T1。
これらのインスタンス タイプを使用している場合は、 preserveClientIpパラメータを に設定しますfalse。
そうしないと、EC2 Instance Connect Endpoint を使用してこれらのインスタンス タイプに接続しようとすると失敗します。
また、クライアントIPを保存するか否かで次に挙げるセキュリティグループの設計にも影響が出てきます。
参考までに、それぞれの設定の場合でOSに記録されるSSH接続のログは以下のようになります。
# preserve_client_ip = false の場合
[root@ip-10-0-2-34 ~]# journalctl -u sshd
Jul 12 04:19:57 ip-10-0-2-34.ap-northeast-1.compute.internal systemd[1]: Starting sshd.service - OpenSSH server daemon...
Jul 12 04:19:57 ip-10-0-2-34.ap-northeast-1.compute.internal sshd[1513]: Server listening on 0.0.0.0 port 22.
Jul 12 04:19:57 ip-10-0-2-34.ap-northeast-1.compute.internal systemd[1]: Started sshd.service - OpenSSH server daemon.
Jul 12 04:19:57 ip-10-0-2-34.ap-northeast-1.compute.internal sshd[1513]: Server listening on :: port 22.
Jul 12 04:23:35 ip-10-0-2-34.ap-northeast-1.compute.internal sshd[1712]: Accepted publickey for ec2-user from 10.0.2.10 port 35430 ssh2: ED25519 SHA256:d/79tJgjydjX8CsFToZdK>
Jul 12 04:23:35 ip-10-0-2-34.ap-northeast-1.compute.internal sshd[1712]: pam_unix(sshd:session): session opened for user ec2-user(uid=1000) by (uid=0)
lines 1-6/6 (END)
# preserve_client_ip = true の場合
[root@ip-10-0-2-196 ~]# journalctl -u sshd
Jul 12 04:28:12 ip-10-0-2-196.ap-northeast-1.compute.internal systemd[1]: Starting sshd.service - OpenSSH server daemon...
Jul 12 04:28:13 ip-10-0-2-196.ap-northeast-1.compute.internal sshd[1515]: Server listening on 0.0.0.0 port 22.
Jul 12 04:28:13 ip-10-0-2-196.ap-northeast-1.compute.internal sshd[1515]: Server listening on :: port 22.
Jul 12 04:28:13 ip-10-0-2-196.ap-northeast-1.compute.internal systemd[1]: Started sshd.service - OpenSSH server daemon.
Jul 12 04:32:24 ip-10-0-2-196.ap-northeast-1.compute.internal sshd[1770]: Accepted publickey for ec2-user from 〓筆者宅のグローバルIPアドレス〓 port 49896 ssh2: ED25519 SHA256:xB3JQn5vzWWelZQ3>
Jul 12 04:32:25 ip-10-0-2-196.ap-northeast-1.compute.internal sshd[1770]: pam_unix(sshd:session): session opened for user ec2-user(uid=1000) by (uid=0)
lines 1-6/6 (END)
設定によって from の後続の値がVPC CIDR内のIP
か接続元クライアントのIP
かで変化していることがわかります。
■セキュリティグループ
EIC Endpoint
と 接続するEC2インスタンス
それぞれに適切なセキュリティグループを割り当てる必要があります。
○EIC Endpointのセキュリティグループ
アウトバウンドに 接続するEC2インスタンス
宛の通信を許可するルールが必要になります。
インバウンドは特に設定する必要はありません。
○EC2インスタンスのセキュリティグループ
アウトバウンドには接続要件に応じた任意のルール
を設定します。(NATゲートウェイ宛など)
インバウンドはEIC Endpointからの通信を許可する必要がありますが、Preserve Client IP
の設定によって必要なルールが少し変わってきます。
クライアントIPの保存 | サポートされているセキュリティグループルール |
---|---|
preserveClientIp=false | ・EIC Endpointセキュリティグループからの受信を許可 ・VPC CIDR からの受信を許可 |
preserveClientIp=true | ・EIC Endpointセキュリティグループからの受信を許可 ・クライアント IP アドレスからの受信を許可 |
※表は公式ドキュメントから引用
注目していただきたいのは、CIDRやIPアドレスで許可設定をする場合はPreserve Client IP
の設定によって設定内容が変わり、セキュリティグループで許可設定する場合は共通しているということです。
セキュリティグループによって接続元IPアドレスを制限したい、というような要件がある場合はPreserve Client IP
を true にすることを検討しましょう。
■権限管理
EIC Endpointを使用した接続に関する権限は IAM によって制御されます。
具体的には、下記のアクションを許可するポリシーをIAM(ユーザー|グループ|ロール)
に付与することで使用することが可能になります。
EC2 Instance Connect
・・・ "ec2-instance-connect:SendSSHPublicKey"
EIC Endpoint
・・・ "ec2-instance-connect:OpenTunnel"
IAMによって権限管理されるということは、クレデンシャルが漏洩したら接族され放題…🤔?
と思われたあなた、心配はごもっともです。
EC2インスタンスのセキュリティグループで制限することも可能ですが、古いインスタンスタイプでPreserve Client IP
がサポートされていない場合はそれはできません。
そんなときは、公式にサンプルが示されていますのでIAMポリシーの Condition句 で制限してあげましょう。
"Condition": {
"IpAddress": {
"aws:SourceIp": "192.0.2.0/24"
},
"NumericEquals": {
"ec2-instance-connect:remotePort": "22"
}
※上記はCondition句だけ抜粋したもの。
■SSM SessionManagerとの使い分け
可用性、コスト、ログの管理、必要なエージェントなど様々な観点から使い分けを検討する必要があります。
これらに関しては偉大なる先人が綺麗にまとめてくださったものがありますのでリンクを貼らせていただきます。
ちょっと試しに触ってみたい方向けterraformコード
実際にEIC Endpoint接続を試してみたい方向けに、terraformのコードを用意しました。
こちらを実行することで、
・ 1 VPC
・ 1 EIC Endpoint
・ 2 subnet
・ 2 EC2 Instance
がそれぞれ作成されます。
作成後はマネジメントコンソールから接続するか、terraformのoutputとして表示されるコマンドを使用して接続してみてください。
コマンドから接続する場合は、AWS CLIを最新版に更新してからお願いします。
おわりに
いかがでしたでしょうか。
EIC Endpointは、
「EC2インスタンスにパブリックIPを持たせたくない」
「SSH鍵の管理をしたくない」
「踏み台サーバーを構築、管理していくのは嫌だ」
という悩みを解決する素晴らしい機能だと思います。
この記事を読まれた皆様も、これを機に導入を検討してみてはいかがでしょうか。