👓

EC2 Instance Connect Endpointを使って踏み台サーバ無しでプライベートなRDS/Auroraに接続する

2023/06/19に公開

追記

現在、この方法は利用することはできなくなっています。

awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"InvalidParameter","Message":"The specified RemotePort is not valid. Specify either 22 or 3389 as the RemotePort and retry your request."}

AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE: Failed to upgrade HTTP connection to Websocket.

モチベーション

今までRDS/AuroraのDBインスタンスにVPC外、例えばインターネットから接続する場合、一般的には踏み台サーバを経由するかパブリックアクセスを有効にする方法が用いられてきました。
しかし、踏み台サーバのコストが気になったり、パブリックアクセスを有効にすることになんとなく抵抗があった方は多いのではないでしょうか?
EC2 Instance Connect Endpointを使用することで、踏み台サーバ無しにプライベートサブネットにあるDBインスタンスに接続ができるようになったので、その方法を紹介してみようと思います。

公式ドキュメントの図で説明すると、この「Instance」の部分がDBインスタンスになるイメージです。


公式ドキュメントより引用

環境

  • AWS CLI version 2.12.1

手順

EC2 Instance Connect Endpointを作成する

マネコンからVPCのコンソールを開き、「エンドポイント」から「エンドポイントを作成」を選択します。

以下の情報を入力します。

  • エンドポイントの名前
  • サービスカテゴリは「EC2 Instance Connect Endpoint」
  • VPC
    • 追加設定で「Preserve Client IP」を有効にするとクライアントIPアドレスがソースIPアドレスとして保持されるようになるらしいですが、今回は割愛します
  • セキュリティグループ
    • DBインスタンスへ接続ができるアウトバウンドルールが必要
    • DBインスタンス側にはこのエンドポイントから接続ができるインバウンドルールが必要
  • サブネット
  • (オプション) タグ

「エンドポイントを作成」を押下します。
エンドポイントのステータスが「保留中」になるので、「使用可能」になるまでしばらく待ちましょう。
また、作成したエンドポイントの「エンドポイントID」を確認しておきます。

AWS CLIから作成する場合はcreate-instance-connect-endpointコマンドを使用します。

AWS CLIでトンネルを作る

aws ec2-instance-connect open-tunnel コマンドを使用することでトンネルを開くことができます。
CHANGELOGによるとAWS CLI v2.12.0で追加されたコマンドのようです。

プライベートなDBインスタンスであれば、DBインスタンスのエンドポイントをdig, nslookupすることでプライベートなIPアドレスを取得できるので、事前に確認しておきましょう。

以下のコマンドでトンネルを開きます。

aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id ${EC2 Instance Connect EndpointのエンドポイントID} --private-ip-address ${DBインスタンスのプライベートIPアドレス} --local-port 3306 --remote-port 3306

以下のように同時にDBインスタンスの名前解決をするのも良いでしょう。

aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id ${EC2 Instance Connect EndpointのエンドポイントID} --private-ip-address $(dig +short ${DBインスタンスのエンドポイント}) --local-port 3306 --remote-port 3306

--remote-port がDBインスタンスのポートです。MySQLだと多くの場合3306だと思いますが、変更している場合はそれに合わせてください。
--local-port はローカル側のポート番号です。何番でも良いのですが、MySQLだと3306にすると楽だと思います。ローカルでMySQLサーバを起動している場合などは適宜変更してください。

接続する

あとはトンネルを経由してデータベースサーバに接続します。
MySQLであれば以下のようなコマンドになります。

mysql -h localhost -u ${user} -p

open-tunnel コマンドで --local-port を3306以外にしている場合は、そのポート番号を指定します。

権限について

EC2 Instance Connect Endpointを使ってトンネルを作る場合に必要な権限については公式ドキュメントを確認してください。

  • ec2-instance-connect:remotePort で接続先のポート番号を制限できます
  • ec2-instance-connect:privateIpAddress で接続先のIPアドレスを制限できます
    • RDS/Auroraの場合、IPアドレスは変化するので、サブネットの範囲で指定するのが良さそうです
  • aws:SourceIp を使えば接続元のIPアドレスを制限できます

参考

Discussion