SSHのローカルポートフォワードを使って22ポートのみ開けたリモートサーバーにpsqlでアクセスする

多段SSHアクセスなどはしてみたことはあるのですが、本を読んでTCPポートフォワードと言うのを初めて聞いて実際にやってみたのでメモ。

今回はSSHのみアクセスが許可されたリモートサーバーのPostgreSQLにローカルマシンからpsqlコマンドでアクセスするのをやってみました。

# 環境

+ ローカルマシン->MacOSX 10.11.4
+ ローカルマシンの環境->psqlコマンドインストール済み
+ ログインマシン->Amazon Linux AMI 2016.03.0
+ ログインマシンの環境->sshd、postgresql-serverのプロセスが起動。アクセスはsshの22ポートのみ許可で公開鍵認証。

# 参考

+ [OpenSSH[実践]入門 (Software Design plus) ](http://www.amazon.co.jp/OpenSSH-%E5%AE%9F%E8%B7%B5-Software-Design-plus/dp/4774168076/ref=sr_1_1?ie=UTF8&qid=1460883684&sr=8-1&keywords=ssh)
+ [17.9. SSHトンネルを使った安全なTCP/IP接続](https://www.postgresql.jp/document/8.4/html/ssh-tunnels.html)

# リモートサーバーにPostgreSQLをインストールする

色々準備します。

```bash
# インストール
$sudo yum install postgresql94-server postgresql94

# データベースの初期化
$sudo service postgresql94 initdb

# サービスの起動
$sudo service postgresql94 start

# Postgresユーザーでログインできるか確認
$sudo su - postgres
$psql

# (以降psqlコマンドでの設定)

# ロール一覧を確認
>¥du
                                         ロール一覧
 ロール名 |                                 属性
 | メンバー
----------+---------------------------------------------------------------------
-+----------
 postgres | スーパーユーザ, ロールを作成できる, DBを作成できる, レプリケーション | {}

# ロール作成
>create role testrole with login createdb password 'testrole';
```

これでローカルホストユーザーからログインできるかと思ったのですが、できませんでした。。。確認するとPostgreSQLのログイン認証方法でパスワード認証がデフォルトを許可していないみたいなので変更します。

[CentOS への PostgreSQL 導入](http://blog.clock-up.jp/entry/2014/12/30/centos-postgresql)

デフォルトの設定が下記のpeerという設定になっているのでmd5に変更します。

+ peer->OSのユーザ名とPostgresSQLのユーザ名が一致していたら受け入れる。デフォルト。localのみ利用できる
+ ident->OSのユーザ名とPostgresSQLのユーザ名が一致していたら受け入れる。
+ md5->パスワード認証。
+ trust->無条件でOK

変更後は以下のようになりました。

```bash
diff pg_hba.conf.org pg_hba.conf
82c82
< host    all             all             127.0.0.1/32            ident
---
> host    all             all             127.0.0.1/32            md5
```

設定後、サービスを起動して確認します。

```bash
# サービス再起動
$sudo service postgresql94 restart

# testroleユーザーでpostgresデータベースにログイン
$psql -h localhost -p 5432 -U testrole postgres
psql -h localhost -p 5432 -U testrole postgres
ユーザ testrole のパスワード:
psql (9.4.6)
"help" でヘルプを表示します.

postgres=>
```

できました。
なお、今回は設定ファイルで一番左がhostとなっているものを変更しましたが、localと書いてあるものもあります。
こちらはUnixドメインソケットの接続を意味するようです。
(psqlコマンドで-hオプションを指定し、先頭を/(スラッシュとしないとUnixドメインでの接続となるらしいですが、それ以外はTCPでの接続のよう)

# 確認のためにローカルサーバーから直接psqlでアクセスする

一度、ローカルサーバー(Mac)から確認のためにpsqlでアクセスしてみます。
（後の検証に関係ないですが、念のため..)

デフォルトではPostgresSQLがTCP接続を受け付けるのはローカルホストからのみのため、それ以外からのTCP接続も受け取れるように設定します。

```/var/lib/pgsql94/data/postgresql.conf

listen_addresses = '*'

```

*とするとことで全てのIPからの許可となります。

**あくまで検証のために** にやっているので、IPアドレスは基本的には制限した方が良いと思います。

設定の反映、確認を行います。

```bash
# サービスを再起動して設定を反映
$sudo service postgresql94 restart

# 確認。0.0.0.0なのでどこからのIPも受け付ける
$netstat -lanput|grep 5432
tcp        0      0 0.0.0.0:5432                0.0.0.0:*                   LISTEN      4244/postmaster
tcp        0      0 :::5432                     :::*                        LISTEN      4244/postmaster
```

では、ローカルマシンから接続して確認してみます。


```bash
# ポート空いているか確認
$telnet 52.196.143.108 5432

# psqlでホストを指定してアクセス
$psql -h 52.196.143.108 -p 5432 -U testrole postgres

```

確認ができたので、元に戻します(ローカルホストからのみのPostgreSQLへのアクセスを許可)

```bash
# 元に戻す
$sudo vi /var/lib/pgsql94/data/postgresql.conf

# 再起動
$sudo service postgresql94 restart

# 変更後、確認
$sudo netstat -lanput|grep 5432
tcp        0      0 127.0.0.1:5432              0.0.0.0:*                   LISTEN      26500/postmaster
```


# SSHのTCPフォワードを使ってアクセスする

早速アクセスしてみます。
-Lオプションの引数は`-L [転送元ポート]:[転送先ホスト]:[転送先ポート]`という形になっています。後は通常sshするときと同じです。

```bash
# -vオプションでデバッグ情報を確認
$ssh -v -L 63333:localhost:5432 ec2-user@52.196.143.108 -i ~/.ssh/xxxxx.pem

debug1: Authentication succeeded (publickey).
Authenticated to xx.xx.xx.xx ([xx.xxx.xxx.xxx]:22).
debug1: Local connections to LOCALHOST:63333 forwarded to remote address localhost:5432
debug1: Local forwarding listening on ::1 port 63333.
debug1: channel 0: new [port listener]
debug1: Local forwarding listening on 127.0.0.1 port 63333.
debug1: channel 1: new [port listener]
debug1: channel 2: new [client-session]
```

これで実際にssh接続されます。
この後、別のローカルのターミナルで以下のコマンドを実行して確認してみます。

```bash
$psql -h localhost -p 63333 -U testrole postgres
```

おお、ログインできます。。。
すごい。。。


なお、以下のように-Nと-fオプションを使うことでバックグラウンドでsshを起動させてポートフォワード目的のみで利用することができます。

+ -Nオプション->リモートでコマンドを実行を行わない(SSHプロトコル2のみ対応)
+ -fオプション->sshをバックグラウンドで起動する

```bash
$ssh -v -N -f -L 63333:localhost:5432 ec2-user@52.196.143.108 -i ~/.ssh/xxxxx.pem
```

参照サイトにも書いてあるようにこれならインターネットを経由する際にはSSHの接続を使っているので暗号化されたトラフィックとなるのがいいですね。