murawaki の雑記

はてなグループから移転してきました

ssh-agent と screen と ForwardAgent

ssh-agentをscreenの中から使う方法(NFS,二重ログイン対応版)を使ってきたが、問題があったのでさらに改造。何とも言えないバッドノウハウ

Steps to reproduce:

  1. 計算機 A1 で ssh-agent を仕込み、ForwardAgent を yes にして B にログイン。すると $HOME/.tmp/ssh-agent/`hostname` は A1 の ssh-agent のソケットへのシンボリックリンクになる。
  2. 計算機 A2 で ssh-agent を仕込み、ForwardAgent を yes にして B にログイン。すると既に $agent がソケットとして機能しているので、これが SSH_AUTH_SOCK に設定される。
  3. A1 から B への接続を切る。A1 の ssh-agent のソケットは消される。
  4. A2 側で ssh-agent が機能しなくなる。

そこで、既にあるソケットを流用する場合には、自分のソケットへのパスを SSH_AUTH_SOCK_OLD に控えておくことにする。接続が切れたときには screen 上で新しい端末を開いたり、update_ssh_agent を直接呼び出したりして SSH_AUTH_SOCK の値を更新すればよい。

しかし、正攻法は B に ssh-agent を常駐させておく方法のはず。そうすれば、A1、A2 からの forwarding に関わらず、B から先にログインできる。そこで、ローカルで ssh-agent が上がっている時にはそちらを優先することにする。さらに処理がぐちゃぐちゃになった。もっと簡単に解決できる予感。

安全性については自信がない。

# ssh-agent を立ち上げるときは init_ssh_agent を呼ぶ
init_ssh_agent () {
    eval `ssh-agent`
    ssh-add
    if [ $? = "0" ]; then
	local agent="$HOME/.tmp/ssh-agent/`hostname`_local"
	ln -snf "$SSH_AUTH_SOCK" $agent && export SSH_AUTH_SOCK=$agent
    else
	echo "init failed"
	return 1
    fi
}

update_ssh_agent () {
    update_ssh_agent_ "$HOME/.tmp/ssh-agent/`hostname`_local" \
	|| update_ssh_agent_ "$HOME/.tmp/ssh-agent/`hostname`"
}

update_ssh_agent_ () {
    local agent="$1"
    if [ -z "$agent" ]; then
	return 1
    fi

    if [ -S "$agent" ]; then
	if [ ! "$SSH_AUTH_SOCK" -ef "$agent" ]; then
	    export SSH_AUTH_SOCK_OLD=$SSH_AUTH_SOCK
	fi

	export SSH_AUTH_SOCK=$agent
	return 0
    elif [ ! -S "$SSH_AUTH_SOCK" ]; then
	echo "no ssh-agent"
	if [ -L "$agent" ]; then
	    rm -rf $agent
	fi
	if [ -n "$SSH_AUTH_SOCK_OLD" ]; then
	    if [ -S "$SSH_AUTH_SOCK_OLD" ]; then
		SSH_AUTH_SOCK=$SSH_AUTH_SOCK_OLD
	    fi
	    unset SSH_AUTH_SOCK_OLD
	    update_ssh_agent
	fi
    elif [ ! -L "$SSH_AUTH_SOCK" ]; then
	# ssh-agent が無効な場合には設定しない
	ssh-add -l >/dev/null \
	    && ln -snf "$SSH_AUTH_SOCK" $agent && export SSH_AUTH_SOCK=$agent
    fi
}