Tagbangers Blog

ローカルマシンから環境を汚さず RDS に接続する

Conclusion

SSM を用いて RDS へのポートフォワーディングを行い、Docker 経由でコマンドを叩く

Motivation

AWS RDS はマネージドなリレーショナルデータベースサービスです

Amazon RDS(マネージドリレーショナルデータベース)| AWS

一般的にリソースはプライベートサブネット上に作成するためローカルマシンから直接クライアントコマンドを用いて接続することはできません

そこで多くの場合は RDS へアクセスできる IAM ロールを持つ踏み台 EC2 サーバを立ててセッションマネージャ等で RDS に接続します

ただし「データのダンプもしくはリストアを行いたい」という要件がある場合に、セッションマネージャだと EC2 内のファイルのやりとりに困ります

下記の方法などを用いることで可能ではありますがデメリットがあります

  • S3 を介して EC2 とファイルやりとりを行う
    • S3 バケットの作成と EC2 へのアクセス権の設定が必要
  • Key Pair を用いて SCP コマンドで EC2 とファイルの転送を行う
    • Key Pair の管理が必要、接続するユーザが ssm-user から ec2-user に変わってしまう

そこで今回は AWS SSM を用いたリモートホストへのポートフォワーディング を用いて、ローカルマシンから RDS に対して直接コマンド操作できるようにするやり方を説明します

また今回は Docker を用いることでローカルマシンにクライアントツールをインストールを回避します、これによりクライアントとサーバのバージョンを合わせつつローカルマシンの環境を汚すことも回避できます

Prerequisite

  • 下記の要件を満たす踏み台 EC2 サーバが用意されている
    • RDS へアクセスできる IAM ロールがアタッチされている
    • EC2 にはバージョン 3.1.1374.0 以上の SSM Agent がインストールされている
  • ローカルマシンに AWS CLI / Docker / Session Manager Plugin がインストールされている

Method

aws ssm start-session を用いてポートフォワードを用います

aws ssm start-session \
  --target "<踏み台 EC2 インスタンスID>" \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters \
'{
  "host": ["<リモートホスト名>"],
  "portNumber": ["<リモートポート番号>"],
  "localPortNumber":["<ローカルポート番号>"]
}'

リモートホスト名 リモートポート番号 は RDS のデータベースページから参照できます

成功すると下記のようなログが流れます

Starting session with SessionId: xxxxx
Port 3306 opened for sessionId xxxxx.
Waiting for connections...

Port 3306 の箇所は ローカルポート番号 で指定したポートになります

実行中の間は該当ポートにクライアントから接続することができます

次に別のシェルを開いて Docker を用いて接続を行います

# MySQL の場合
docker run --name <コンテナ名> --rm -it mysql:5.7 /bin/bash
mysql -h host.docker.internal -P <ポート番号> -u <DB ユーザ名> -p

# PostgreSQL の場合
docker run --name <コンテナ名> --rm -it postgres:11 /bin/bash
psql -h host.docker.internal -p <ポート番号> -U <DB ユーザ名>

mysql:5.7 postgres:11 の箇所は RDS で利用しているバージョンに合わせてください

ホストオプションで host.docker.internal を指定することで Docker コンテナ内からローカルマシンのネットワークにアクセスすることができます

※ macOS でのみ検証しているため、他 OS では異なる可能性があります

別途ダンプファイルのやり取りを行う場合は2通り方法があります

# コマンドでファイルの転送のやり取り
docker cp /path/to/dump.sql $(docker ps -qf "name=<コンテナ名>"):/path/to/dump.sql

# Volume マウントをアタッチ
docker run -v /path/to/workspace:/path/to/workspace --name <コンテナ名> --rm -it ...