keychainでssh-agentと鍵を管理することにした

鍵を本体外に出したので、ssh 接続のたびに鍵ファイルを指定するのがだるくなってしまった。面倒なのはいけない。そこで ssh-agent を使うことにした。

ssh-agentをなんとなく避けていた

ssh-agent は今までなんとなく避けていた。というのも

ssh-agentってメモリ内にパスフレーズそのまま保存してるんじゃないの?

と思っていたから。ということはハイバネート状態のノートからは生のパスフレーズが抜き取れるよね、という話にたどり着いて、そんなあぶないもの使いたくないとか思っていたんだけど、そもそも

PC本体内に秘密鍵があるので本体奪われたらagent使っていようがいまいが一緒

という状態に目をつぶって頑なにagentを拒否していても意味がない。

ということで颯爽とポリシーを変更した。

本当は秘密鍵を抜き取ったことだし、今まで通り ssh-agent を使わない運用ならだいぶ安全になると思うんだけど、逆に接続のたびに USB メモリが必要だと結局 USB メモリ刺しっぱなしになりそうで、それだとまったく意味がない。分離した意味を持たせたうえで面倒なく運用するにはやはり agent を使った方がよさそうだ。

ssh-agentってしっくりこないんです!

  • ssh-agent は秘密鍵とパスフレーズを保持してくれる
  • ssh-agent とのやりとりは ssh-agent 自身ではサポートしてくれない
  • SSH_AUTH_SOCK と SSH_AGENT_PID を使った古典的な方法で、そのままでは shell が変わったら使えない
  • ssh-agent の多重起動も簡単に起きてしまう

ちなみにいちばん簡単な使い方は

  1. eval `ssh-agent` で起動する
    • ssh-agent は起動すると自身の管理に使える環境変数(のセット方法)を出力して daemon 化する。ここでこの出力を eval すると変数がセットされて、その shell 内では ssh-agent とやりとりできるようになる。
  2. ssh-add で鍵を教える
    • このとき必要ならパスフレーズを入力する

の2アクションを行えば、以降の ssh 接続では何もする必要がなくなる。

とは言え shell が変わったら使えなくなるのはきつすぎる。screen 起こしたらアウトだもの。

OSX標準のkeychainってしっくりこないんです!

OSX には 10.5 辺りから ssh 接続のときに GUI でダイアログが出てパスフレーズを記憶しようとしてくれる keychain さんがいる1。ssh-agent を使いたくなかったのでこれも ~/.zshrc で

unset SSH_AUTH_SOCK

して殺していた。この記述を外して使ってやればいいじゃんと思ったりもしたが、

  • ssh 接続を hook して起きてくるので、接続しようとするまで ssh-agent は起きていない
  • ということは本体外に追い出してしまった鍵ファイルの場所を教える方法がない2
  • パスフレーズをシステムのキーチェーンに保存したいわけじゃない

ということでやっぱり黙っていてもらうことにした。

別途keychainをインストールする

Mac のキーチェーンじゃなくてこれ。

Keychain - Funtoo Linux

MacPorts でも Homebrew でもインストールできる。

ここで言う keychain の目的の一つは上で挙げた ssh-agent の shell をまたげないという問題を回避する方法を提供することで、もう一つは ssh-agent の多重起動も防止すること。何度呼び出しても ssh-agent は増えない。つまり、

  1. ssh-agent を起動してSSH_AUTH_SOCK と SSH_AGENT_PID をファイルに吐き出す
  2. ssh-agent を管理する

上の機能を提供してくれる。

実際に keychain を活用するには keychain をインストールして起動するだけではやっぱりダメで、自分の使っている shell の rc ファイルに上の 1 で吐き出されたファイルの存在チェックと、存在した場合の読み込み処理を追記してやる必要がある。

何を書けばよいかは man を読めば分かる。

OSX 標準のものを殺しつつkeychainを利用する

どこでもいいんだけど man にある通り ~/.keychain に agent 関係のファイルを保存することにしたので、

if [ ! -f $HOME/.keychain/$HOSTNAME-sh ] ; then
    unset SSH_AUTH_SOCK
fi

こんな感じで

  1. 自分で起こした keychain の使うファイルがあれば SSH_AUTH_SOCK はそのまま使う
    • でないと ssh-agent とやりとりできない
  2. 存在しない場合は OSX 標準の keychain を呼ぼうとしてうざいので SSH_AUTH_SOCK は消しちゃう

ということにした。それ以外にも hostname を screen さんやいろんな人が利用していたりして結構面倒なことになっていたが、ようやく整理できた。

使い方

今はどうしているかというと、

  1. USBメモリを刺す
  2. eval `keychain –eval`
  3. ssh-add /Volumes/PATH/TO/KEY
  4. パスフレーズを入力
  5. USBメモリを抜いて片付ける

で、快適生活してます3

長時間席を外すときには

keychain -k all

しておくと安心。

  1. どうやら SSHKeychain と言うらしく、/usr/sbin/systemkeychain が正体かな? そこから /usr/bin/ssh-agent -l を起動する。 

  2. と思ったけど ssh -i で教えられるな…。忘れてた。 

  3. ssh-add を keychain でやることもできる 

More