理系学生日記

おまえはいつまで学生気分なのか

keychain を導入した

ssh でのログインで一々パスワードを入力するのは正直メンドい。そもそも ssh でパスワードを要求されるのはパスワード認証であるから、これを RSA/DSA 認証を行うように変えてやればパスワードは要求されない。すごい。これでみんなが幸せになれる。
しかし、RSA/DSA 認証は公開鍵・秘密鍵を使用する認証方法であり、秘密鍵がその名の通り秘密にされることが前提になっている。簡単に言うと、秘密鍵が悪意のある第三者に盗まれると死ぬ。これを防ぐため、秘密鍵を使用しているのが間違いなく本人でありますですよということを主張するために、秘密鍵はパスフレーズによって暗号化される。これによってセキュリティは強化されるが、秘密鍵を使う度にユーザはパスフレーズの入力を要求されることになる。

ssh でログインする度にパスフレーズを要求されるのでは、少くとも操作的にはパスワードを使っていたときと何も変わらないではないかということで、よくパスフレーズを空にする方法が使われる。
パスフレーズを空にすることで、(remotehost:$HOME/.ssh/authorized_keys を適切に設定してやれば)無入力でのログインが可能になる。

個人的には、個人用途であればこれで別に良いじゃねーかおれは腹が減ってんだからそっちの方が重要だろがとは思うんだけど、ときどき「パスフレーズなしとは何事か」と突っ込まれるので ssh-agent + keychain の構成を取ることにした。

ssh-agent

ssh-agent は、秘密鍵を"復号化された状態で"キャッシュしてくれるデーモンだと思えば良いと思う。秘密鍵を復号するために、ssh-add で一度だけパスフレーズを入力する必要はあるが、以後ずっと復号化された秘密鍵を持ち続ける。リモートホストに接続する際、ssh は ssh-agent とよしなに会話して復号化された秘密鍵を取得してくれるので、パスフレーズの入力の必要はない。よかった、これでみんな幸せになれる。

$HOME/.{bash,zsh}rc などに

eval $(ssh-agent)

とか書いとけば良い。これでシェル起動時に ssh-agent を使用する準備は整うので、あとは一度だけ ssh-add を使ってパスフレーズを入力すれば良い。

ssh-agent の使い方としては上記がおそらくスタンダードな方法だと思うのだけれど、これだとシェルを起動する度に ssh-agent が立ち上がる。気付かない間に ssh-agent が 200 個立ち上がってました、とか笑える。新規に立ち上げた ssh-agent に対して逐一 ssh-add するとか笑える。いや笑えない。明日 M-1 ですから、笑いは M-1 に取っておかないといけない。そういうマズいところを解決するために keychain がある。

keychain

そもそもなんで ssh-agent をシェル起動の度に立ち上げるのかというと、UNIX ソケット等の情報を環境変数で他プログラムに渡すってところが理由なんだと思う。
ssh-agent をコマンドラインで叩くとこの辺りが良くわかるが、ssh-agent は標準出力に対して環境変数を export する命令を出力する。

% ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-iToNHNgED7/agent.1034; export SSH_AUTH_SOCK;
SSH_AGENT_PID=1035; export SSH_AGENT_PID;
echo Agent pid 1035;

そのため、このシェルから起動されたプログラムでなければ上記の情報を使えない。

keychain は、ファイルにこれらの情報を永続化させておくことでこの問題を解決する。keychain は起動後、既に ssh-agent が立ち上がっているかを確認して、立ち上がってなければ立ち上げる。このとき、ソケットや PID の情報をファイルに保存しておく。必要に応じてこのファイルを参照してくれるので、ssh-agent が立ち上がっている限り、もうパスフレーズを入力する必要は一切なくなる。これでみんな幸せになれる。
$HOME/.zshrc とかにでも

/path/to/keychain > /dev/null 2>&1

とか書いとけば良い。