ssh-agent を一つのシステム上で使い回す
SSH の秘密鍵にパスフレーズを設定すると、何度もパスフレーズを入力するのが面倒になるので ssh-agent を使いたくなるわけだが、単純にシェルの初期化スクリプトに eval `ssh-agent`
と書いておくだけだと、複数のシェルを同時に起動したときに個別に ssh-agent が起動してしまってパスフレーズが共有されなかったり、ssh-add するのをうっかり忘れて ssh-agent が持ち腐れになってしまったりする。ググるとこれに対処するためのシェルスクリプトが色色見つかるが、どれもしっくりくるものがなかったので自作してみた。
(注: Keychain やその類のツールが使える環境では素直にそちらを使った方がよいと思われる。)
方針は、シェルが起動した時にどうこうするのではなくて、実際に ssh を使う時に必要に応じて ssh-agent を起動し ssh-add を実行すること。ssh と ssh-agent が通信するためのソケットのファイル名を固定することで SSH_AUTH_SOCK 環境変数に頼らずソケットのファイル名を指定すること。
一度 ssh-agent が起動するとシェルを終了した後も ssh-agent はシステム上に居残り続けるので使う人はその積りで。下記シェルスクリプトを実行可能なテキストファイルとして ssh という名前で保存し、本来の ssh コマンドよりも先に PATH が通っているところに配置すればよい。最終行の /usr/bin
は実際に本来の ssh コマンドがある場所に合わせて書き換えること。
通常通りシェルから ssh コマンドを起動しようとすると本来の ssh コマンドの代わりにまずこのスクリプトが実行される。このスクリプトは ssh-agent が起動していなければ起動し、ssh-agent に鍵が登録されていなければ登録した後、本来の ssh コマンドを起動する。
このスクリプトは ssh だけでなく scp や sftp に対しても使える。
#!/bin/sh
checkopt() {
case "$1" in
-h|-\?|--help)
false;;
-f|-t)
test x"${0##*/}" != x"scp";;
*)
true;;
esac
}
if [ $# -gt 0 ] && checkopt "$1"; then
if ! [ x"${SSH_AUTH_SOCK:+set}" = x"set" ]; then
SSH_AUTH_SOCK=~/.ssh/@$(uname -n)
if ! [ -e "$SSH_AUTH_SOCK" ]; then
(umask 022; ssh-agent -a "$SSH_AUTH_SOCK" >/dev/null) || exit
fi
export SSH_AUTH_SOCK
fi
if [ x"${SSH_AUTH_SOCK:+set}" = x"set" ] && ! ssh-add -l >/dev/null 2>&1
then
({ command exec </dev/tty; } 2>/dev/null; ssh-add -t 1d) || exit
fi
fi
exec "/usr/bin/${0##*/}" "$@"
SSH_AUTH_SOCK=~/.ssh/@$(uname -n)
の個所でソケットのファイル名を指定している。一つのファイルシステムを複数のホストで共有している場合を考慮し、ファイル名にホスト名を含ませている。これによりホストごとに個別の ssh-agent が使われる。
ssh-agent が起動しっぱなしになるのが嫌な人は使い終わってから kill すればよい。kill コマンドのデフォルトである SIGTERM シグナルを使うこと。
(2009 年 1 月 2 日改訂)
| 固定リンク
コメント