💻

ssh-agentの使い方と注意点の備忘録

2024/08/01に公開

リモートサーバー上でGitリポジトリ操作するとき、クライアント端末に保管してあるGit用のSSH鍵をリモートサーバーにコピーして、git clone ..してましたが、もちろん良くない。

ssh-agentの仕組みと使い方が、やっと分かってきたので備忘録残しときます。

試した環境

  • クライアントは、Windows11 + VSCode + Remote-SSH
  • リモートサーバーは、Ubuntu20.04
  • リポジトリは、GithubとホスティングしているGitLabの2つ

ssh-agentについて

このエージェントは、クライアント端末上でサービスとして稼働していて、SSH鍵を登録しておくことができる。
リモートサーバー上で必要になった時に、このエージェントが登録した鍵を提供してくれて、リモートでSSH鍵が使える。リモート上にSSH鍵は存在しないので、セキュアであるという仕組み。

Windows11クライアントでssh-agentをセットアップする

ssh-agentはサービスとして常時稼働させておく。Windows11の場合は、すでにインストールされているので、管理者権限でPowerShellを起動して開始設定を行う。
この操作は1回だけやればOK。サービスとして以降常駐することになる。

普段はVSCode + Remote-SSHでログインしてるけど、サービスで稼働しているので常に利用できるようになる。

登録したら、Get-Service ssh-agentでRunningになっているか確認する。

> Get-Service ssh-agent | Set-Service -StartupType Automatic
> Start-Service ssh-agent

> Get-Service ssh-agent

Status   Name               DisplayName
------   ----               -----------
Running  ssh-agent          OpenSSH Authentication Agent

ssh-agentにSSH鍵を登録する

ssh-addコマンドでSSH鍵を複数登録する。
SSH鍵や接続情報は%USERPROFILE%\.ssh\で管理しているはずなので、ここにあるSSH鍵のパスを指定して登録する。ここで登録する必要がある鍵は、あくまでリモートサーバー上で必要になる鍵だけでOK。

> ssh-add /path/to/ssh-key-file

クライアント端末で、現在登録されている鍵の確認する。表示される内容は鍵の種類で異なる。SSH鍵ファイルの末尾にあるコメントも出力される。後述するフィルタ機能で重要になるので、なるべく特定できるコメントになるようにしておく。

> ssh-add -l
4096 SHA256:xxxxxxxxxxxxx hoge@hoge.com (RSA)
2048 SHA256:xxxxxxxxxxxxx huga@huga.com (RSA)

ちなみに、削除する方法は、-d {鍵}-Dで一括削除できる。

> ssh-add -d /path/to/ssh-key-file
> ssh-add -D

リモートサーバーへのSSH接続設定

リモートサーバーへSSH接続する際、SSHエージェントをリモートへ転送する設定を行う必要がある。
接続情報が%USERPROFILE%\.ssh\configに保存されている場合、各ホストの接続情報にForwardAgent yesを追加しておくと、リモートサーバーにSSHログインしたときに、自動的にエージェントが転送されて、登録した鍵を参照することができる。

Host remote-server
	HostName XXX.XXX.XXX.XXX
	Port 22
	User hoge
	IdentityFile ~/.ssh/hoge
	ForwardAgent yes

全設定でまとめて転送する場合は

Host *
	ForwardAgent yes

を追加しておくと良い。

リモートサーバー上で鍵の確認

ここまで設定できたら、リモートサーバーにSSHログインして、鍵が見えている確認する。
ssh-add -lコマンドを実行して、クライアント端末で実行したときの同じ情報が表示されればOK。

> ssh remote-server

hoge@xxx: ~$ ssh-add -l

4096 SHA256:xxxxxxxxxxxxx hoge@hoge.com (RSA)
2048 SHA256:xxxxxxxxxxxxx huga@huga.com (RSA)
  1. VSCode上でコマンドパレットを起動
  2. Remote-SSH: ホスト上のVS Code Serverを強制終了するを実行
  3. 該当するホストを選択して、起動中のプロセスを削除する
  4. もう一度Remote-SSHでログインしなおす

で解消できる。

リモートサーバー上でGitの操作確認

Githubに接続するために必要なSSH鍵をssh-addで登録してある状態で、リモート端末上で、Githubのリポジトリからクローン等できることを確認する。

> git clone ssh://git@github.com/user/repository.git

Cloning into 'repository'...
remote: Enumerating objects: xxx, done.
remote: Counting objects: 100% (xxx/xxx), done.
:
Resolving deltas: 100% (xx/xx), done.

上記は、リモートサーバー上にSSH鍵はもちろんconfigファイルがなくてもクローン出来るようになるので、セキュアである。

ポート番号がデフォルト22番じゃないGitリポジトリサーバー

Gitリポジトリサーバーをホスティングしている場合などで、ポート番号がデフォルト22番じゃない場合。例えば、hoge.huga.com:1234で稼働している場合は、

> git clone ssh://git@hoge.huga.com:1234/user/repository.git

ポート番号を付けてクローンする。

Githubアカウントを仕事用、プライベート用2つ持っている。ssh-agent設定だけでは片方の接続に失敗する

Githubへの接続ユーザは、全ユーザgitである。じゃあどうやって識別しているのかというと、GithubはSSH公開鍵で識別している。なので、2つのアカウントで同じ鍵を登録することはできない。

ローカル端末では以下のようにして、仕事用/プライベート用のGithub接続情報をconfigファイルに定義していれば、Host識別子でssh接続することで切り替わるので問題ない。

Host github.job
	User git
	HostName github.com
	IdentityFile ~/.ssh/user1.key
  IdentitiesOnly yes

Host github.private
	User git
	HostName github.com
	IdentityFile ~/.ssh/user2.key
  IdentitiesOnly yes

ssh -Tで接続テストしてみると、アカウントが切り替わっていることが分かる。

# 仕事用
ssh -T git@github.job
Hi user1 ! You've successfully authenticated, but GitHub does not provide shell access.

# プライベート用
ssh -T git@github.private
Hi user2 ! You've successfully authenticated, but GitHub does not provide shell access.

ところが、この2つの鍵をssh-addで登録した後、リモートサーバーでGithubに接続するとうまく動作しない。正確にいうと、後で登録したSSH鍵を使うGithubアカウントのアクセスがうまくいかない。下記の場合、user2の鍵を使うアクセスがNG。

> ssh-add ~/.ssh/user1.key
> ssh-add ~/.ssh/user2.key

おそらく、user1.key, user2.keyと順番に試しているのか、1つ目の鍵でアクセスできたが認証に失敗?してuser2.keyを試してくれないような感じだと思われる。

解決方法は、

  • ssh-agent-filterインストールする(リモートサーバー)
  • 鍵のフィルタリングするコマンドをcore.sshcommandオプションで追加する

まずリモートサーバーにssh-agent-filterをインストールするが、おそらくgitと一緒にインストールされている可能性が高い。

> sudo apt install ssh-agent-filter

次にクローンするときにgit configのオプションを追加する。めんどくさいが1回だけなので、我慢する。

--configユーザ名メールアドレスSSH鍵のフィルタリングを指定してクローンすると、git configのローカル設定としてリポジトリに登録される。

> git clone \
--config user.name="user2" \
--config user.email="user2@huga@huga.com" \
--config core.sshcommand="afssh --comment huga@huga.com --" \
git@github.com/user2/repository.git

ユーザ名とかメールアドレスのスイッチングは.gitconfigでもできるが、こちらの方がシンプルで分かりやすい。うっかり、会社のメールアドレスで、プライベートリポジトリをコミットするなどの誤爆をしなくて済む。

SSH鍵が複数あるローカルPCの場合

core.sshcommandのところで直接利用する鍵を指定する。

> git clone \
--config user.name="user2" \
--config user.email="user2@huga@huga.com" \
--config core.sshcommand="ssh -i ~/.ssh/github-key1 -F /dev/null" \
git@github.com/user2/repository.git

Discussion