ProxyCommand

自分の作業環境の作り直しをしているのですが、
たまに理解が怪しくなるので、確認ついでにここに吐き出しておこうと思います。

背景

リモート環境にあるホストAにsshあるいはscpするためには、
 踏み臺(Bastion)となるホストXに一度SSHログインしないとならない

というケース/環境はそこそこ多いと思います。

これがsshなのであればまあ、ssh X -> ssh Aとするだけなのでそこまででもありませんが、
scpだった場合は概ねこんな手順になりますよね。

  1. まずssh XとしてホストXにログイン
  2. ホストX上でscp -p A:/path/to/datafile ~/(オプションはお好み)
  3. コピーが終わるのを待ってから、Xからログアウト
  4. scp -p X:~/datafile .
  5. コピーが終わるのを待ってssh X rm ~/datafile

これで何が困るかというと、

  • コピー(scp)が2回必要なので、時間が餘計にかかる
  • 1回目のコピーが終わったことに気づかず、あるいは終電 業務時間が終了するなどして、さらに時間がかかる
  • ホストXの空き容量がたりないときがある
    • 分割したり、X以外に使えそうなホストを探し回ったり作ったりと餘計な時間やコストがかかる
  • ホストX上の一時ファイルを消し忘れる ←
    • むしろ「もしもの時のためにとっておこう、用が済んだらあとで消そう」などと積極的に殘してしまう
    • そして忘れる1
    • 結果ホストXのディスクが一杯になって他の利用者や管理者に怒られる

こうなるからです。2

これは手動のときだけの話ではなく、
定期的にscpを実行させたいときや、スクリプトやバッチ処理時にsshでコマンド実行しないとならないときにも問題になります。

本來ならば、データ受け渡しのための仕組みをちゃんと用意すべきところではありますが、逆に(様々な事情で)恆常的な仕組みを設けられない場合もありますし、一時的なメンテナンスや調査等でしか必要にならない場合、「そこまでしなくても…」と思ってしまうのも人情というものではないでしょうか。

ProxyCommandに-Wオプションという救世主

定番中の定番という話ではあるのですが、
ProxyCommandを使えば、ワンライナで実行できます。

1
$ ssh -oProxyCommand='ssh -W %h:%p X' A
1
$ scp -p -oProxyCommand='ssh -W %h:%p X' A:/path/to/datafile .

ProxyCommand中の%h %pが、
本來の接続先である A とそのポート(無指定だとデフォルトの 22)に置換される、という動作になります。

実例としてはこんな感じになるかと。

1
$ ssh -oProxyCommand='ssh -W %h:%p [email protected]' [email protected]
  • Host X ... ec2-13-112-xxx-xxx.ap-northeast-1.compute.amazonaws.com
  • Host A ... ip-172-31-xxx-xxx.ap-northeast-1.compute.internal

鍵指定(-i)やポート番號の指定(-P9022-oPort=9022等)といったオプションも、
勿論上記コマンドラインの中に含めることが可能です。

その際は、
ホストXに対するオプションをProxyCommand內に、
ホストAに関するものを外側(-oProxyCommandと同列)に記述してください。

なお、実際にAにアクセスするのはXなので、
コマンドを実行するホストがAのホスト名を名前解決できなくても構いませんし、
勿論ホスト名ではなく、IPアドレスで書いても構いません。

むしろ注意すべきなのは、ワンライナで書こうともAに接続するのはあくまでXなので、
Xが名前解決・接続できるようにAを指定(ホスト名、IPアドレス)する必要があるというところです。

要は普段Xで実行している內容そのままを記述すればいいのですが、
一方でSSHとしてAにログインする、つまりホストAと鍵の交換を行うのは手元のホストになるので、
鍵の置き場やknown_hostsの記述などは、ホストXではなく手元の環境になります。

関係する全インスタンスのユーザやSSH鍵が同じならそこまで問題にはならないでしょうけど、
インスタンス先によってユーザや鍵が変わる場合は若干ややこしいですね。。。

~/.ssh/configに記述して楽をする

このような操作をそこそこ繰り返し行うなら、~/.ssh/configに記述してしまえば楽になります。

といいますか、そういった話はさすがに定番どころの設定なので、Developers.IOでも何回か記事になっていて參考になります。

蛇足がてら付け加えるなら、ssh_configHostパターン指定ができるので、

~/.ssh/config
1
2
Host *.compute.internal 172.31.*
  ProxyCommand  ssh -W %h:%p X

のように、VPC內のホストはすべてホストX経由で接続する…という記述しておくとより楽です。

例えば上述の例で言えば、

~/.ssh/config
1
2
3
4
5
Host *.compute.internal
  ProxyCommand  ssh -W %h:%p ec2-13-112-xxx-xxx.ap-northeast-1.compute.amazonaws.com
 
Host *
  User        ec2-user

としておくことで、下記のように短くなります:

1
$ ssh ip-172-31-xxx-xxx.ap-northeast-1.compute.internal

ちなみに

この指定方法は、Ansibleやrsync等、バックエンドにssh/scpを使っているコマンドにも有効です。

參考:

また直接関係はありませんが、このような踏み臺ホストは頻繁にアクセスすることになるので、
ControlMasterなども設定するとより幸せになれたことを併せてご報告いたします。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章