AWS EC2 からしか接続できない RDS Aurora MySQL に外部から接続してみる

最近 AWS を触り始めた。

Amazon RDS で MySQL 互換の Aurora を構築してあって、この Aurora に接続できるのは踏み台となる EC2 インスタンスのみ、という構成の環境を作った。

つまり、

  1. EC2 インスタンスに SSH 接続する
  2. 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 オプションだけだと接続している間はずっとターミナルのプロンプトが戻らないので、-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 ポートフォワーディングが必要になる。時々必要になるのでよく覚えておこう。