SSHポートフォワーディングでローカルから外部サーバーへアクセスする
投稿日:
環境
- amazonlinux:2017.03-with-sources
- Dockerコンテナのベースイメージです。
- sshクライアント用のソフトはyumでインストールしてあるとします。
やりたい事
ローカル環境(Docker)で動かしているアプリケーションから
アクセス制限のかかっているAPIサーバーやDBサーバーへアクセスしたかったので
SSHポートフォワーディングを使って実現しました。
SSHポートフォワーディングを使えば、自分が特定のポートで受けた通信を特定のサーバー(SSHで入れる事が条件)を経由して別のサーバーへ受け流す事ができるようになります。
コマンドは以下のように実行します。
ssh -f -N -L {自分が待ち受けるポート}:{アクセスしたいサーバーのIPやホスト名}:{アクセスしたいサーバーのポート} -i {SSHするための秘密鍵のパス} {SSH先のユーザー}@{SSH先のサーバー} -p {SSHポート} -4
(sshのオプション説明は調べればすぐ出てくるので割愛します)
例えば以下のようにコマンドを打つと
自分が10080ポートで受けた通信はserver2経由でserver1の80ポートに流して、そのレスポンスをそのままリクエスト元に戻す
という意味になります。
なお、server2はポート22でec2-userユーザーにSSH接続できるものとします。(秘密鍵認証)
ssh -f -N -L 10080:server1:80 -i ~/.ssh/id_rsa ec2-user@server2 -p 22 -4
手順
①純粋なポートフォワーディングを使う
下図のような通信イメージです。
- WEBアプリのコンテナにてSSHポートフォワーディングを実行。
- WEBアプリから自身の3306ポートへ通信が発生したらポートフォワーディング発動し、
ssh.server.com経由でdb.server.com:3306へアクセスする。 - WEBアプリから自身の10443ポートへ通信が発生したらポートフォワーディング発動し、
ssh.server.com経由でapi.server.com:443へアクセスする。
WEBアプリが動いているDockerコンテナ内にてSSHポートフォワーディングのコマンドを実行します。
ssh -f -N -L 3306:db.server.com:3306 -L 10443:api.server.com:443 -i /path/to/secret_key user@ssh.server.com -p 22 -4
あとはアプリケーション内で以下の箇所を変更すればポートフォワーディングでアクセスできるようになります。
・「db.server.com:3306」の通信箇所を「localhost:3306」へ通信するよう変更
・「api.server.com:443」の通信箇所を「localhost:10443」へ通信するよう変更
②踏み台コンテナを利用してポートフォワーディングする
もし上記①のアプリケーション変更箇所がソースコードにハードコーディングされている場合など、
変更が困難な場合はこちらの手順で対応します。
下図のような通信イメージです。
- 踏み台コンテナにてSSHポートフォワーディングを実行。
- WEBアプリから踏み台コンテナの3306ポートへ通信が発生したらポートフォワーディング発動し、
ssh.server.com経由でdb.server.com:3306へアクセスする。 - WEBアプリから踏み台コンテナの443ポートへ通信が発生したらポートフォワーディング発動し、
ssh.server.com経由でapi.server.com:443へアクセスする。
踏み台専用のDockerコンテナを作成し、コンテナの実行コマンドとしてSSHポートフォワーディングのコマンドを実行するようにします。
※プロセスがバックグラウンドに行かないように、fオプションを外しています。
ssh -N -L 0.0.0.0:3306:db.server.com:3306 -L 0.0.0.0:443:api.server.com:443 -i /path/to/secret_key user@ssh.server.com -p 22 -4
あとはWEBアプリが動いているコンテナのhostsに
『db.server.com』と『api.server.com』が踏み台コンテナのIPアドレスとなるように記載します。
踏み台コンテナのIPアドレスは以下のコマンドで調べられます。
nslookup {踏み台コンテナ名} | grep Address | tail -n +2 | cut -f2 -d ' '
シェルスクリプトにするとこんな感じになります。
#!/bin/bash -eu
HUMIDAI_IP=`nslookup humidai | grep Address | tail -n +2 | cut -f2 -d ' '`
echo "${HUMIDAI_IP} db.server.com" >> /etc/hosts
echo "${HUMIDAI_IP} api.server.com" >> /etc/hosts
これでSSHポートフォワーディングを使った通信の設定は完了です。
補足
ポートフォワーディングを使ってアクセスしたいサーバーがDBサーバーだけであれば
①の手順のコマンドを実行後、②のようにhostsを記載してdb.server.comを127.0.0.1(自身)にしてしまえば良いです。
しかし、APIサーバーのようにWEBアプリと同じポート(443)への通信をポートフォワーディングしたい場合、
既にWEBアプリで使っているポートをSSHポートフォワーディングでも待ち受ける事はできないので、
②の手順のような踏み台コンテナが必要となります。