AWS EC2 からしか接続できない RDS Aurora MySQL に外部から接続してみる
最近 AWS を触り始めた。
Amazon RDS で MySQL 互換の Aurora を構築してあって、この Aurora に接続できるのは踏み台となる EC2 インスタンスのみ、という構成の環境を作った。
つまり、
- EC2 インスタンスに SSH 接続する
- EC2 インスタンスにインストールしておいた
mysql
コマンドで Aurora MySQL に接続する
という接続方法が順当な手順になるが、SSH ポートフォワードでもう少し楽に接続できないか試してみた。
目次
用意する SSH Config ファイル
ポートフォワードを行うので、次のような SSH Config ファイルを書いてやれば良い。
Host ec2-tunnel-rds
HostName 【EC2 の Public IP】
User ec2-user
IdentityFile ~/.ssh/id_rsa.pem
LocalForward 13306 【RDS 名】.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306
EC2 と SSH 接続したら、LocalForward
で RDS との接続ポートを指定し、ローカル端末から RDS までの接続を作ってやる。分かりやすくするため、ローカル側のポートは 13306
としてある。
このようにポートフォワーディングを使って、対象のサーバとの接続を作ることを「トンネルを掘る」と表現したりする。
もしも、EC2 インスタンスに接続するために別の踏み台サーバが存在する場合は、ProxyCommand
で中継してやれば良い。
# 踏み台サーバ
Host bastion
HostName 【踏み台サーバの Public IP】
User bastion-user
IdentityFile ~/.ssh/bastion.pem
Host ec2-tunnel-rds
HostName 【EC2 の Private IP】
User ec2-user
IdentityFile ~/.ssh/id_rsa.pem
ProxyCommand ssh -W %h:%p bastion
LocalForward 13306 【RDS 名】.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306
こんな風に書いてやれば OK。EC2 インスタンスが Public IP を持たず、Private IP でしか接続できないような場合であれば、こうやって踏み台を経由する。
バックグラウンドで SSH 接続する
SSH Config を用意したので、コレを使って SSH 接続し、トンネルを掘ってやる。
$ ssh ec2-tunnel-rds -fN
-N
オプション :ssh
コマンド実行後、接続先サーバのプロンプトを開かないようにする-f
オプション :ssh
コマンド実行後、バックグラウンドで接続する
-N
オプションだけだと接続している間はずっとターミナルのプロンプトが戻らないので、-f
オプションも付けてバックグラウンド実行するようにしている。
バックグラウンドで接続している ssh
プロセスを終了するには ps aux | grep ssh
で対象のプロセス ID を確認して kill 【プロセス ID】
する。
とりあえず、事前にこのようにトンネルを掘っておいてから、MySQL クライアントで接続する。
mysql
コマンドで接続する
ローカル端末に mysql
コマンドがインストールされていれば、次のようなコマンドで接続できるはずだ。
$ mysql -h 127.0.0.1 -P 13306 -u 【ユーザ名】 -p【パスワード】
ポートフォワード設定のとおり、127.0.0.1
(= localhost) の 13306
ポートに接続するようにしている。
mysql
の -p
オプションは、-p
オプションだけ指定すると、コマンド実行後にパスワードを聞いてくれる動作をするので、本来はココでパスワードを入力した方がセキュアだ。
しかし、-p【パスワード】
と、スペースを開けずにパスワードを書くことで、プロンプト表示なしに接続できるのだ。例えばパスワードが MyPass
だったら、スペースを開けずに -pMyPass
と書くワケだ (もしくは --password=MyPass
でも良い)。
コレでうまく繋がるはず。
Docker の MySQL イメージを利用して接続してみる
ローカル端末に mysql
コマンドをインストールしていない場合は、Docker の MySQL イメージで代用しても良いだろう。少し書式にクセがあるので注意が必要だ。
予め SSH ポートフォワードした後、次のように docker
コマンドを実行していく。
# MySQL イメージを取得しておく
$ docker pull mysql:latest
# MySQL 接続する
$ docker run -it --rm mysql:latest mysql -h host.docker.internal -P 13306 -u 【ユーザ名】 -p【パスワード】
-h
で指定するホストは 127.0.0.1
ではなく、host.docker.inetrnal
とする。Docker コンテナ内の localhost ではなく、Docker が動作しているホストマシンを指したいので、このような書式になっている。
ポート番号を指定する -P
や、その他のオプションは通常の mysql
コマンドと同じ。
その他、--rm
を指定することで、コマンド終了時 (MySQL 切断時) にコンテナを破棄するようにしている。
以上
外部から直接接続できる RDS であれば
$ mysql -h 【RDS 名】.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u 【ユーザ名】 -p【パスワード】
$ docker run -it --rm mysql:latest mysql -h 【RDS 名】.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u 【ユーザ名】 -p【パスワード】
こんな風に接続できるのだが、ネットワーク上の制約がある場合は、今回のように SSH ポートフォワーディングが必要になる。時々必要になるのでよく覚えておこう。