ssh-agent(1)の機構はあまりに素朴過ぎて使いづらいので、実用と現実逃避を兼ねてssh-agent-proxy(1)なるものを作った。例によってRubyで書いたプロトタイプだけど、一応動くので公開。

 こいつは何かというと文字通りssh-agent(1)のプロクシだが、ポイントは二点。

  1. それ自身がSSH認証エージェントとして動き、固定パスにソケットを開く。
  2. クライアントからの接続があると、その場で利用可能な本物のエージェントソケットを探し、通信を中継する。

 1により、SSH_AUTH_SOCKには常に固定値を設定すればよくなる。(これはssh-agent(1)でも-aオプションで指定すれば可能) そして2によって、いつでも動的にその時点で利用可能なエージェントソケットを探してつないでくれる。

 これがどのように役に立つのかと言えば、たとえばこういうときだ。いつものように、リモートホストにエージェント転送をオンにしてSSH接続したとしよう。そこでscreen(1)を起動し、作業をする。この段階では、問題なくエージェント転送が効いている。ところが、ここで不慮の、あるいは意図的な切断によって、SSH接続が切れてしまったらどうなるか。screeenおよびその子プロセスが持つSSH_AUTH_SOCKは、もはや無効なソケットを指した状態で取り残されてしまう。後で再び同ホストにSSH接続し、保存されたscreenセッションに接続(attach)しても、新しい(転送)エージェントのソケットは使われず、古いSSH_AUTH_SOCKが指すソケットにつなごうとして失敗するだけだ。手で同環境変数の値を更新するしかないが、これはシェル関数(やEmacs用のelisp関数)を用意したとしても非常に面倒な作業だ。

 そんな憂鬱も、ssh-agent-proxy(1)を使えば一発で解決する。リモートホストのログインスクリプト内に、次のように書いておく:

eval $(ssh-agent-proxy 2>/dev/null)

これだけ。*1あとは、勝手にそのときそのとき使えるソケットに中継してくれる。multi-tty版Emacsだけを飼うscreenセッションを裏に置いておけば、いつでもemacsclientで瞬時にエディタが起動し、trampvcpclでのSSH接続も無問題。

 もちろん、転送元ホストでもssh-agent-proxyを使うメリットはある。もし何らかの理由によって、ssh-agentのインスタンスが死んでしまったりソケットが消えてしまったりしても、慌てずに新しくssh-agentを起動するだけでいい。(もちろん続いてssh-addも必要) 仮にssh-agent-proxy自身が死んでしまったとしても、やはり起動し直せば問題ない。

 まだβ版ですが、0.0.1のタグを打っておいたので興味のある人は試してみてください。


Categories : Tech