話題の記事

EC2 Instance Connect Endpoint経由でRDSに接続してみた

2023.06.15

2023/06/28 追記 : 利用可能ポートが制限されました

EC2以外への接続はAWSとして意図していなかった模様で、本日時点で宛先のポート番号がTCP 22、TCP 3389以外だと

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."}

という旨のエラーが出る様になりWebSocket接続が切断されます。

The specified RemotePort is not valid. Specify either 22 or 3389 as the RemotePort and retry your request.

とある様にSSH接続かRDP接続のみの利用に制限されています。
残念ながら現在は本記事の様な使い方は出来ませんのでご了承ください。

公開当時の内容

しばたです。

前に書いた記事でEC2 Instance Connect Endpointの接続はWebSocketトンネルを介したものであると説明しました。
また、プロトコルもSSHだけに制限されておらずRDPも使用可能でした。

AWS CLIの実装を読み解く限りこの機能のメインはWebSocketトンネルを張る事でありプロトコルにも依存していません。
そうなると「別にEC2インスタンスに限らず、たとえばRDSインスタンスに対してもトンネルを張れるのでは?」と考えるのは必然でしょう。

試してみた

というわけで実際に試してみました。

検証環境

前回の記事で用意したVPC環境にRDS for PostgreSQL 15.3のインスタンスを用意しました。

RDS for PostgreSQLを選んだのは単純に私が使い慣れてるだけであり他のRDBMSでも問題ないでしょう。
その他の情報は以下の通りです。

  • VPC内のPrivateサブネットはインターネットアクセス不可
  • RDS for PostgreSQL 15.3はSingle AZ構成で待ち受けポートはデフォルトのまま(TCP 5432)
    • パラメーターグループとオプショングループはデフォルトのものを使用
    • セキュリティグループでVPC Endpointからの接続(TCP 5432)を許可
  • VPC EndpointのセキュリティグループでTCP 5432のアウトバウンド通信を許可
  • クライアント環境でAWS CLIを利用可能に初期設定済み
    • your_profileという名前のプロファイルを設定済み

補足1 : VPC Endpointのセキュリティグループ設定

VPC Endpointセキュリティグループのアウトバウンド通信制御はこんな感じになっていればOKです。
RDSインスタンスに対してTCP 5432で通信するためアウトバウンド通信を許可しておきます。

インバウンド通信は全てブロックして構いません。

補足2 : RDSインスタンスのセキュリティグループ設定

RDSインスタンス側のセキュリティグループはVPC Endpointからのインバウンド通信を許可しておきます。

1. aws ec2-instance-connect open-tunnel コマンドの実行

接続までの手順はWindows ServerにRDP接続した時とほぼ同じです。

最初にクライアントでaws ec2-instance-connect open-tunnelコマンドを使用しRDSインスタンスに対してWebSocketトンネルを張ります。
このコマンドの基本的な使い方は--instance-idパラメーターで宛先EC2インスタンスIDを指定しており、このままではRDSに接続できません。

基本的な利用方法

# EC2インスタンスIDを指定してWebSocketトンネルを張る
aws ec2-instance-connect open-tunnel --instance-id "宛先インスタンスID" --remote-port 3389 --local-port "任意の空きポート"

上記指定をした際は

  • 宛先インスタンス情報からインスタンスのPrivate IPアドレスを取得
  • 宛先インスタンスの配置されているVPCおよびサブネット情報からVPC Endpointを探索する

といった作業を内部で行っています。
WebSocketトンネルを張るのに必要な情報は「VPC EndpointのPublic DNS名」「宛先Private IPアドレス」「宛先ポート番号」「ローカルポート番号」であり、このうち「VPC EndpointのPublic DNS名」「宛先Private IPアドレス」の2つをどうにかしてコマンドに渡してやる必要があります。

「宛先Private IPアドレス」はRDSのDNSエンドポイントを名前解決してやれば取得できます。

# 例えばPowerShellからだとこんな感じでRDSの名前解決が可能 : 今回の環境では 10.0.21.157 がRDSのIPアドレス
PS C:\> Resolve-DnsName -Name test-postgres.xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -Type A | Select-Object IPAddress

IPAddress
---------
10.0.21.157

そしてありがたいことにこのコマンドには--instance-connect-endpoint-id, --private-ip-addressパラメーターが存在しています。
「VPC EndpointのPublic DNS名」は--instance-connect-endpoint-idを指定してやればコマンド内部で取得してくれます。 *1

このため以下の指定でWebSocketトンネルを張ることができます。

今回の利用方法

# VPC Endpoint IDおよび宛先Private IPアドレスを直接指定してトンネルを張ることも可能
aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id "VPC Endpoint ID"--private-ip-address "宛先Private IP"--local-port "任意の空きポート" --remote-port 5432

実行例はこんな感じ。

# 今回の実行例
PS C:\> $env:AWS_PROFILE="your_profile"
PS C:\> aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-xxxxxxxxxxxx --private-ip-address 10.0.21.157 --local-port 15432 --remote-port 5432

設定に問題がなければエラー無くWebSocketトンネルが張れるはずです。

2. RDSインスタンスへ接続

あとはlocalhost:15432 (127.0.0.1:15432)に接続すればPostgreSQLを操作できます。

(pgAdmin 4で接続する場合)

(VPC EndpointのIP 10.0.21.136 から接続された扱いになっている)

最後に

以上となります。

今回はRDSを例にしましたがVPCからIPv4で到達可能であれば様々なAWSリソースに対して接続できるはずです。
無限に応用できると思いますので是非活用してみてください。

脚注

  1. ちなみに--instance-connect-endpoint-dns-nameパラメーターも存在し、直接Public DNS名を引き渡すことも可能です