セッションマネージャー over SSH 経由でプライベートサブネット内のRDSへ接続する方法

# 概要
プライベートサブネット内に立てた Amazon RDS には、グローバル DNS が発行されないため、ローカルから AWS 上の RDS への接続はできません。

そんなときはセッションマネージャーとプライベートサブネット内の EC2 経由で RDS へ接続することができます！！！！

# この方法で接続できる前提条件
下記条件を満たしている環境の場合、セッションマネージャーを利用してリモート RDS へ接続することができます。

- プライベートサブネット内に**踏み台用の EC2** が起動されていること
- EC2 内に**セッションマネージャーがインストール**されていること
- EC2 内の **ec2-user に公開鍵を配置**していること

コンテナ環境のみや踏み台サーバを RDS と同じ VPC 内に建てられない場合、公開鍵を配置できない場合はこの方法では接続できませんのでご注意ください。

# 構成概要図
下記のようなルートで**リモートの RDS** へ接続できます。

![portforwarding.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175476/f15383a9-7138-68fe-9c6b-a2f01af4c302.png)

## なぜセッションマネージャーにさらに SSH 接続しているか
SSH コマンドのポートフォワード機能を使うのでどうしても SSH 接続が必要だったから。
DB クライアントから接続する場合、「セッションマネージャから接続するかたへ」みたいに便利な接続方法を提供しているわけではありません。
なので普通の TCP/IP 接続で接続できるように、SSH を利用したポートフォワーディングを設定しています。

しかし、セッションマネージャーで EC2 に接続するのでセキュリティグループには SSH のポートを許可する必要はありません。

参考：
[セッションマネージャー越しにSSHアクセスすると何が嬉しいのか](https://dev.classmethod.jp/articles/ssh-through-session-manager/)


# 設定内容
では詳しく設定コマンドを記述していきます。

## 前提
下記の設定を事前に完了している必要があります。

- AWS CLI のインストールと config の設定。
- 踏み台サーバ内にセッションマネージャーをインストール。
- RDS のセキュリティグループに EC2 のセキュリティグループを登録。
- ec2-user に SSH 接続用の公開鍵を登録。

参考：
※ セッションマネージャーをインストールされていない方はこちらを参考に
[Systems Manager セッションマネージャを使ったら SSH 管理不要になった](https://qiita.com/syoimin/items/6f5f0aca002161d40233)

## ローカルにセッションマネージャーをインストール
ローカルの端末に**セッションマネージャーをインストール**します。
今回は Mac を想定しています。

```sh
$ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
$ unzip sessionmanager-bundle.zip
$ sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
$ session-manager-plugin
```

他の OS の場合は下記公式サイトを参考してください。
[(オプション) AWS CLI 用の Session Manager plugin をインストールする](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)

## ssh config の設定
SSH の config ファイルに**セッションマネージャーをプロキシーとした SSH の設定**を記述します。
**HostName** は踏み台サーバの **EC2 インスタンスの ID** になります。
**profile** は AWS CLI を利用するときに設定する `~/.aws/config` に記載されている対象 **AWS アカウントのプロファイル名**を指定します。
profile を指定しない場合は **default アカウント**が適応されます。

```sh
# vi ~/.ssh/config
host remote-ec2
    HostName i-xxxxxxxxxxxxxxx
    Port 22
    User ec2-user
    IdentityFile ~/.ssh/id_rsa.pem
    ProxyCommand sh -c "env PATH=/usr/local/bin:$PATH aws ssm start-session --profile <プロファイル名> --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

```

## SSH の接続確認
踏み台 EC2 への接続確認を行います。
もし、多要素認証を設定している場合はここで認証コードを聞かれますので、入力してください。

```sh:多要素認証なし
$ ssh remote-ec2
# ログインが成功し、リモート EC2 のIPアドレスが表示されたら接続成功。
# [ec2-user@ip-xx-xx-xx-xx ~]$ 
```

```sh:多要素認証あり
$ ssh remote-ec2
Enter MFA code for arn:aws:iam::xxxxxxxxxxxx:mfa/syoimin: 
# [ec2-user@ip-xx-xx-xx-xx ~]$ 
```

## ポートフォワーディングを実行
最後に **SSH コマンドでポートフォワーディングのプロセスを実行**します。
このプロセスが実行中の間は**ローカルの 33306 番ポート**に対して**リモート RDS の 3306 番ポート**にポートフォワーディングされます。

```sh
$ ssh -N remote-ec2 -L 33306:xxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306
```

## DB クライアントでリモート RDS へ接続
接続の準備が整ったので、実際に **リモートの Amazon RDS へ接続**してみます。
下記の設定項目は **MySQL Workbench を参考**にしています。

```接続情報
Connection Method: Standard(TCP/IP)
Hostname: 127.0.0.1
Port: 33306
Username: <DB ユーザ名>
Password: <DB パスワード>
Default Schema: <データベース名>
```

**接続先ホスト**はローカルIP。
**接続先ポート**は先程ポートフォワードした接続元のポート番号になります。
他の DB クライアントやコマンド等でも同様に上記アクセス情報でアクセスできると思います。

# 感想
セッションマネージャーで SSH のポートワードできることは知っていましたが、ポートフォワードを使ってどうにかして ローカルの DB クライアントからリモートの RDS への接続ができないかなと思い悪戦苦闘していました。

踏み台の EC2 インスタンスと SSH の鍵が必要にはなりますが、セッションマネージャー経由なので踏み台用の EC2 インスタンスには SSH のポートを一切開けなくて済みます。
セキュアな状態を保ったままリモートの RDS へ接続できるのでこの方法が今の所ベストな方法ではないのかなと思います！！！

今回は、DB クライアントから接続したかったので SSH のポートフォワーディングを使った接続方法で接続しました。
コマンドラインだけだとセッションマネージャや AWS CLI 単体だけで接続できると思うので、コマンドラインで済ませる方はここまで複雑なことはやらなくていいかもです。