SSHした先のサーバでも、手元の ssh の認証情報を使いたい場合、 ssh-agent を使うのが一般的です。例えば、下記のような場合に有用です。
- パブリックIPアドレスを持たない裏側にいるサーバに、一旦別サーバを経由してから ssh する場合
- ssh したサーバで、 ssh を使った
git clone
をしたい場合
使用方法
Linux の場合
❯ eval `ssh-agent -s`
❯ ssh-add ~/path/to/key
として、同じターミナルの同じセッション内のみで、 ssh -A user@host
で鍵転送が行える。ssh-agent
の標準出力を eval することが必要。
Mac の場合
❯ ssh-agent
❯ ssh-add ~/path/to/key
とすると、別のターミナルを開いても ssh -A user@host
として鍵転送が行われて ssh することが出来る。Linux と違って eval は不要。
何が違うのか?
ssh -A
したとき、環境変数の SSH_AUTH_SOCK
に入っているUNIXドメインソケットを見て、鍵情報の転送が行われます。もしその環境変数に値が入っていないと転送は行われません。
ssh-agent
自体はバックグラウンドで動作するプロセスで、 SSH_AUTH_SOCK
のソケット経由でデータをやり取りしています。
ssh-agent
コマンドを実行すると、下記のような出力になります。
❯ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-XXXXXXXXXXX/agent.1234; export SSH_AUTH_SOCK;
SSH_AGENT_PID=1234; export SSH_AGENT_PID;
echo Agent pid 1234;
これを実行すると、 SSH_AUTH_SOCK
と SSH_AGENT_PID
が環境変数にセットされます。この状態で ssh-add
や ssh -A
を行うと、 SSH_AUTH_SOCK
がどこにあるか分かるので実行できます。
これは Mac でも Linux でも同じような標準出力になります。
ただし、Mac の場合はなぜかターミナルの別のセッションでも ssh-add
や ssh -A
が実行できています。何故なのでしょうか?
SSH_AUTH_SOCK の扱い
Mac では、 echo $SSH_AUTH_SOCK
すると、/private/tmp/com.cpple.launchd.XXXXXXXX/Listeners
という文字列が表示されます。
ssh-agent
のソケットはここで Listen して ssh-agent
のプロセスに渡すということのようです。
このため、$SSH_AUTH_SOCK
がどこからでも見えて透過的に使えます。
逆に複数のセッションで ssh-agent
をしても、 $SSH_AUTH_SOCK
はそのうちの1つということになります。ただし、 ssh-agent
のプロセス自体はコマンド実行回数分だけ起動してしてしまいます。
Linux の挙動が良いか、Mac の挙動が良いか、は一長一短という感じに見えます🙂
いずれにしても、 ssh-agent
が必要な作業が終わったら killall ssh-agent
でプロセスを終了しておきましょう。
❯ killall ssh-agent
Linux でも Mac のような挙動にするなら
ソケットのパスを固定すれば同じ挙動にすることも出来ます。
例えばシェルの設定ファイル等 (.zshenv
等) で、SSH_AUTH_SOCK
を固定してしまいます。
export SSH_AUTH_SOCK=/tmp/ssh-agent.sock
ssh-agent
起動時にソケットのパスを渡せるので、下記のようにして起動します。
❯ ssh-agent -a $SSH_AUTH_SOCK
あとは、他のセッションでも $SSH_AUTH_SOCK
が固定されているので Mac のように使えます。
ただ、 ssh-add
した鍵が全部転送されたりデメリットもあるので、僕は冒頭に書いたように eval
してそのセッション内のみで使うような運用にしています。好みの問題ですね🙃
初めて ssh-agent
を使ったのが Mac だったので、WSL2 で開発環境構築していたら期待通りに動かずはじめ困惑しました。細かい部分で差異があり、なかなか面白いです😎