2013年6月19日水曜日

sshを使い、踏み台越しのweb閲覧、scpを実現


 sshを使い以下2つを実現することを目的とする
 ◆ 踏み台サーバ経由のweb閲覧
 ◆ 踏み台サーバ経由のscp

 ※linuxでiptablesを使い同様のことを実現することもできるだろう
 (参考) iptablesでhttp, ssh通信をNAPTしてフォワーディング



踏み台サーバ経由のweb閲覧
● 目的
localは自分がいる環境であり、仮にwindowsを使っているとする。
step1はssh(22/tcp)ポートをオープンしているlocalからのアクセスを許可する
踏み台サーバである。

step2はssh(22/tcp)ポートをオープンしているstep1からのアクセスを許可する
踏み台サーバである。
つまりstep1とstep2の2つの踏み台がある。

server1はhttp(80/tcp)を提供しているサーバであり、
step2からしか閲覧を許可していない。

この状況でlocalからブラウザでserve1のWEBコンテンツを閲覧する。

これはsshのポート転送(ポートフォワーディング)を利用して実現できる。
多段sshログインとも呼ばれているやつである。


● 簡易構成
+-------+
| local | 
+-------+
   ↓
+-------+
| step1 | 踏み台サーバ
+-------+ ssh(22/tcp)
   ↓
+-------+
| step2 | 踏み台サーバ
+-------+ ssh(22/tcp)
   ↓
+-------+ 
|server | web公開サーバ
+-------+ http(80/tcp)


● 実現手段
sshを利用して接続する。

+-------+
| local | 10080/tcp  ssh -L 10080:localhost:20080 username@step1・・・①
+-------+
   ↓
+-------+
| step1 | 20080/tcp  ssh -L 20080:server:80 username@step2・・・②
+-------+ 
   ↓
+-------+
| step2 | 
+-------+
   ↓
+-------+
|server | 
+-------+


①はlocalで実施する。
puttyなり、teratermを使っていれば、
ソースポートを10080/tcp、
送り先をstep1:20080/tcp
にして、step1へssh接続すればばよい。
localで10080/tcpポートが開く。
step1上で20080/tcpポートがこの段階で開くわけではない。

②はstep1にて実行する。
step1の20080/tcpポートにアクセスし、step2経由で、
server1の80/tcpへ接続する。

以上の対応でlocal上でserverのhttp(80/tcp)コンテンツを閲覧できる。
http://localhost:10080/



踏み台サーバ経由のscp
● 目的
collectサーバにserver1~2サーバ上のログをscpを利用して収集する。


● 簡易構成
      +-------+
      |collect| ログを収集するサーバ
      +-------+
          ↓
      +-------+
      | step  | 踏み台サーバ
      +-------+ ssh(22/tcp)
          ↓
+-------+   +-------+
|server1|   |server2| ログのある各種サーバ群
+-------+   +-------+ ssh(22/tcp)


●  手動試験1
collect上で以下コマンドを実施し、
まずは、server1サーバ上のログを取得する。
collectの10022/tcpポートにアクセスし、step経由で、
server1の22/tcpへ接続する。
# ssh -p 22 -t -t -L 10022:server1:22 root@step

あとは、collect上でローカル上の10022番ポートへ接続すれば
server101サーバの/var/log/test_srcファイルを
collectサーバの/var/log/test_dstとしてscpできるはずである。
# scp -P 10022 root@localhost:/var/log/test_src /var/log/test_dst


●  手動試験2
server102のログも取得する。
既に利用している10022ポートは使えないため、別のポートを利用するか、
または先ほどのコネクションを切っておく。今回は後者を選択するとする。
# ssh -p 22 -t -t -L 10022:server2:22 root@step

あとはscpするだけだが、今回は警告が出て接続ができないはずである。
# scp -P 10022 root@localhost:/var/tmp/test_src /var/tmp/test_dst
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

最初、collectはlocalhost(自分)に接続してstepのポート転送によってserver1へ接続した。
今回、collectは同様にlocalhost(自分)に接続しているにもかかわらず、
ポート転送によってserver2へ接続し、ホストとIPが一致していないと判断される。
~/.ssh/known_hostsで管理される情報に相違が出ているためである。
今回はこのファイルを編集するのではなく、UserKnownHostsFileキーのオプションで回避する。
ついでにStrictHostKeyCheckingキーも付与して初回ログイン時の接続案内yes/noも出なくする。

# scp -o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-P 10022 root@localhost:/var/tmp/test_src /var/tmp/test_dst


● 自動化
collect上のcronなどに登録させて定期バッチ処理としてさせる必要も出てくるだろう。
例として以下のようなツールを動かせばいいだろう。
パスフレーズの自動入力はexpectを利用してscpを自動化を参考にしてほしい。
#!/bin/sh

YESTERDAY=`date --date '1 days ago' '+%Y%m%d'`

for num in `seq 1 2`
do
  /usr/local/bin/ssh_auto.sh server${num} & 

  # sshでコネクションを張り終えるまでに少し時間がかかることを考慮する
  sleep 5

  /usr/local/bin/scp_auto.sh localhost /var/log/log*${YESTERDAY}* /var/log/

  pid=`ps aux | grep "spawn ssh -p 22 -t -t -L 10022" | grep -v grep  | awk '{print $2}'`
  kill $pid
done
内部で使っているssh_auto.sh, scp_auto.shツールは 先のリンクを元に容易に作れるだろう。 




(関連)