MANA-DOT

PIXEL ART, PROGRAMING, ETC.

ssh-agentのforwardを利用し、ホストマシンとローカルVMの非公開鍵を共有する

ssh-agentはずっと利用していたものの、agentのforwardという機能をつい最近まで知リませんでしたが、ローカルVM開発する上でかなり便利な機能でしたので書きます。

ssh-agentのforwardを利用すると、例えばVM開発する上で、ホストマシンの非公開鍵を使用してゲストマシンでsshを利用できたりします。特に、github複数の鍵登録する必要がなくなるのが便利。

ssh-agentとは

リモートマシンにSSHでログインする際、最もよく利用する方式は公開鍵認証であると思います。 公開鍵認証では、あらかじめログイン先に登録しておく公開鍵と、ローカルマシンにおいておく非公開鍵のペアを用いますが、非公開鍵には通常パスフレーズを設定すると思います。

この、パスフレーズの入力を、シェルにログインした時の一回のみで済ませ、以後の入力を省いてくれるのがssh-agentの仕事になります。Agentはパスフレーズ入力後に常駐し、以降の公開鍵認証が必要な場面で認証を代わりにやってくれるイメージです。

forward-agentとは

ホストマシンのssh-agentをログイン先のマシンからも参照できるsshの機能です。 これを利用することで、githubなどいろいろなところに登録されたホストマシンの公開鍵を、ローカルVMからも利用することができ、開発の際に捗ります。

利用方法

ssh-agent

ssh-agentはそのままコマンドで叩くと、プロセスに常駐しつつ以下の様な出力を行います。

SSH_AUTH_SOCK=/tmp/ssh-dX4G7kvpdh04/agent.9172; export SSH_AUTH_SOCK;
SSH_AGENT_PID=10776; export SSH_AGENT_PID;
echo Agent pid 10776;

sshコマンドがagentを利用するために必要な環境変数をエクスポートしつつ、PIDの出力を行っています。これをシェルで評価することで、必要な環境変数を得るという寸法です。

ssh-agentが常駐している状態で、ssh-addコマンドを叩くことで、そのagentに鍵を覚えさせることができます。

シェル起動時にssh-agentを起動し、またssh-agentを複数のシェルで利用したいので、ファイルに出力し、これら環境変数がなかった場合にssh-agentを起動するように.zshrcに記述します。

こちらを参考にしました。

SSH_AGENT_FILE="$HOME/.ssh-agent-info"
test -f $SSH_AGENT_FILE && source $SSH_AGENT_FILE
if ! ssh-add -l >& /dev/null ; then
  ssh-agent > $SSH_AGENT_FILE
  source $SSH_AGENT_FILE
  ssh-add
fi

これで、シェル起動時にagentが起動していればそのagentを利用し、起動していなければ起動して非公開鍵のパスフレーズの入力を求められるようになります。この状態でsshを実行すると、鍵のパスフレーズの入力を求められないことがわかります。

現在agentで管理されている鍵は、ssh-add -lすることで参照できます。

2048 ### 省略 ### /home/mana/.ssh/id_rsa (RSA)

Forward Agent

以上でagentが利用可能となっているシェルで、ssh-Aオプションまたは、sshのconfigでForwardAgent yesを設定していると、ホストマシンのssh-agentをログイン先でも利用できるようになります。

ログイン先でssh-add -lすることで、ホストと同じ鍵を参照できることがわかります。

2048 ### 省略 ### /home/mana/.ssh/id_rsa (RSA)

tmuxとの兼ね合い

以上でログイン先でもssh-agentを利用できるのですが、このままではひとつ問題があります。

ログイン先でtmuxなどを利用している場合で既存のセッションにアタッチした場合、そこでは環境変数が以前のssh-agentを参照しており、結果としてssh-agentの利用ができなくなります。 この問題に関しては、こちらが詳しかったのです。

結論から言うと複数ログインを考慮しないぶんには(今回はローカルVM想定なので)、ssh-agentのソケットをシンボリックリンクとして、tmuxからは常にそのシンボリックリンク経由で利用できるようにしてやれば良いようです。

それを加味すると、ssh-agentの起動スクリプトは次のようになりました。

AGENT_SOCK_FILE="/tmp/ssh-agent-$USER"
SSH_AGENT_FILE="$HOME/.ssh-agent-info"
if test $SSH_AUTH_SOCK ; then
  if [ $SSH_AUTH_SOCK != $AGENT_SOCK_FILE ] ; then
    ln -sf $SSH_AUTH_SOCK $AGENT_SOCK_FILE
    export SSH_AUTH_SOCK=$AGENT_SOCK_FILE
  fi
else
  test -f $SSH_AGENT_FILE && source $SSH_AGENT_FILE
  if ! ssh-add -l >& /dev/null ; then
    ssh-agent > $SSH_AGENT_FILE
    source $SSH_AGENT_FILE
    ssh-add
  fi
fi

$SSH_AUTH_SOCKが定義済みかつ、シンボリックリンクと異なる場合に、張り替えてあげるという処理を行います。

同じ.zshrcをホストマシンでもローカルVMでも利用したかったため、無理やり混ぜ込んだ形になりました。

vagrantからの利用

vagrantvagrant sshVMにログインする場合、以下の記述をVagrantFileに追加することでForwardAgentが利用できるようです。

config.ssh.forward_agent = true

参考リンク