こんにちは!エンタープライズクラウド部クラウドコンサルティング課の日高です。
もし私のことを少しでも知りたいと思っていただけるなら、私の後輩が書いてくれた以下のブログを覗いてみてください。
今回は、EC2 Instance Connect Endpointを利用しポートフォワーディングでPrivate Subnet内のRDSに接続する方法について記載していきます。
はじめに
以下のような要望をお客様からいただきました。
- EC2 Instance Connect Endpointを利用してポートフォワーディングでPrivate Subnet内のRDSに接続したい!
ですので今回は、「EC2 Instance Connect Endpointを利用してポートフォワーディングでPrivate Subnet内のRDSに接続する方法について」の作業手順をまとめたいと思います。
EC2 Instance ConnectとSSMの利用用途や使い分け等については本ブログには記載ないので、その内容が気になる方は以下の弊社ブログをご覧ください。
検証環境の構成図
構成
検証環境の全体像を、ざっくり示すと以下のような環境です。
「こちらの構成図に書いてあるリソースは構築済み」 かつ「AWS CLIのインストールも完了済み」 の前提で話を進めていきたいと思います。
ポートフォワーディングの全体像
ポートフォワーディングに該当する箇所を抜き出して、詳細に記載した構成図が以下です。
こちらの構成を今回は作っていきたいと思います。
作業内容
localhost→EC2接続のためのSSH トンネルの確立
上記の構成図のように、「トンネルを作成し2222番ポートでEC2 Instance Connect Endpointにアクセスしたら、EC2 Instance Connect Endpoint経由でEC2の22番ポートに転送する」設定を以下コマンドで行います。
aws ec2-instance-connect open-tunnel --instance-id <インスタンスID> --remote-port 22 --local-port 2222
- aws ec2-instance-connect open-tunnel :AWS EC2 Instance Connect Endpoint を使用して、ローカルマシンからリモートの EC2 インスタンスに SSH トンネルを確立するためのコマンド
- --instance-id: 接続したい EC2 インスタンスの ID を指定します。
- --remote-port: リモートの EC2 インスタンスのポート番号を指定します(通常 22)。
- --local-port: ローカルマシンのポート番号を指定します。このポートがトンネルのエンドポイントとなります。
上記のコマンドを実行することで、以下の流れで設定が行われます。
- WebSocket トンネルの作成
・ローカルマシンと EC2 Instance Connect Endpoint の間に WebSocket トンネルを確立します。このトンネルを通じて、SSH 接続が確立されます。 - SSH トンネルの確立
・WebSocket トンネルの内部で、SSH トンネルを確立します。これにより、ローカルマシンからリモートの EC2 インスタンスへの安全な SSH 接続が可能になります。 - ポートフォワーディングの設定
・指定されたローカルポート(--local-port)とリモートポート(--remote-port)の間でトラフィックを転送します。
コマンドの実行結果として、以下のように帰ってくれば成功です。
$ aws ec2-instance-connect open-tunnel --instance-id <インスタンスID> --remote-port 22 --local-port 2222 Listening for connections on port 2222.
SSH を使用して EC2 インスタンスに接続
上記の構成図のように、「ローカルマシンからリモートの EC2 インスタンスに接続し、さらにその EC2 インスタンスを経由して AWS RDS データベースにアクセスするためのトンネルを作成する」設定を以下コマンドで行います。
ssh -i <キーペアのパス> ec2-user@localhost -p 2222 -L 5432:<DBのホスト名>:5432
- ssh:SSH(Secure Shell)プロトコルを使用して、安全なリモートログインを行います。
- -i <キーペアのパス>:EC2 インスタンスに接続するためのキーペアファイルを指定します。このキーペアは事前に AWS で作成したものです。
- ec2-user@localhost:ec2-user は、Amazon Linux や一部の AMI でデフォルトのユーザー名です。他の AMI を使用している場合は、異なるユーザー名(例:ubuntu や centos)を指定する必要があります。ocalhost は、ローカルマシンを指します。この場合、トンネルが設定されているため、実際にはローカルポート 2222 を介してリモートの EC2 インスタンスに接続します。
- -p 2222:ローカルマシンのポート 2222 を使用して、EC2 インスタンスに接続します。このポートは先に aws ec2-instance-connect open-tunnel コマンドで設定したものです。
- -L 5432:<RDSのホスト名>:5432:ローカルマシンのポート 5432 を、リモートの Aurora データベースのポート 5432 にトンネルします。この設定により、ローカルマシンのポート 5432 に接続するアプリケーション(例:pgAdmin4)は、実際には RDS データベースに接続されます。
上記のコマンドを実行することで、以下の流れで設定が行われます。
- SSH 接続の確立
・ローカルマシンのポート 2222 からリモートの EC2 インスタンスへの SSH 接続が確立されます。 - ポートフォワーディングの設定
・ローカルマシンのポート 5432 とリモートの Aurora データベースのポート 5432 の間にトンネルが作成されます。
・これにより、ローカルマシン上のアプリケーションは、localhost:5432 を使用してリモートの RDS データベースに接続できます。
RDSに接続を試す(pgAdmin 4)
最後に、pgAdmin4 を使用して、ローカルホストのポート 5432 で RDS データベースに接続します。
これにより、トンネルを経由して RDSにアクセスが可能になります。
無事、接続が完了しました。
補足(接続元IPアドレスで通信を制御する方法)
この作業をしながら私が考えていたことは以下です。
「以下のコマンドを実行することができる状態になったら(AWS CLIを実行するための情報が流出してしまうなど)、簡単にRDSのデータを操作することができてしまうのではないか?」
aws ec2-instance-connect open-tunnel --instance-id <インスタンスID> --remote-port 22 --local-port 2222
もちろん、AWS CLIに用いているクレデンシャル情報の管理が厳格であったり、AWS CLIで利用するIAMユーザーやIAMロールのCondtion句で制限をかけていればセキュリティは担保できます。
とはいえ、心配な箇所もあるので、EC2 Instance Connect Endpointへの通信を接続元IPアドレスで通信を制御する方法がないのかを調べました。
ただ、上記の構成図のようにAWS CLIコマンドで「localhost→EC2接続のためのSSH トンネルの確立」を実行するコマンドはAWSのサービスエンドポイントを経由しています。
そのため、利用者側で通信を制御することはできません。
ただ、さすがAWSさんです。接続元IPアドレスで通信を制御する方法を作ってくれていました。
EC2 Instance Connect Endpointの設定画面を見てみると「クライアントIPの保持」という設定があります。
EC2 Instance Connect EndpointのENIに付与しているセキュリティグループで通信を絞ることはできませんが、この設定を有効にすることで、以下の画像のようにEC2のセキュリティグループ側で通信を絞ることが可能でした。
まとめ
EC2 Instance Connect Endpointを利用したポートフォワーディングでPrivate Subnet内のRDSに接続する方法について記載してみました。
本記事が誰かの助けになれば幸いです。
日高 僚太(執筆記事の一覧)
2024 Japan AWS Jr. Champions / 2024 Japan AWS All Certifications Engineers
EC部クラウドコンサルティング課所属。2022年IT未経験でSWXへ新卒入社。
記事に関するお問い合わせや修正依頼⇒ hidaka@serverworks.co.jp