s64's blog

1Password SSH Agentで複数GitHubアカウントを使う

他社と協業してのソフトウェア開発を生業としている場合、個社の事情によりGitクレデンシャルを個別に用意しなければいけないケースが往々にして存在する。そしてそのベアリポジトリは全てgithub.com、なんてことも珍しくない。つまるところ、GitHubのアカウントを複数発行し管理する必要が出てくるということだ。
そしてGitHub上のソフトウェア資産は言うまでもなく個社すべてにとって重大な機微情報であるからして、これらへのアクセスを許すこととなるSSH鍵は1PasswordのようなVaultに保管しておいて然るべきであろう。

ではこのGitクレデンシャルの堅実な保管と、個社毎でクレデンシャルを切り替える、というのは如何にして実現すればよいか。本稿ではこれを実践する。

1Password SSH Agent

1Passwordには「1Password SSH Agent」という機能がある。SSH鍵を1Password内で暗号化保管し、接続時に自動的に適切な鍵を提供する仕組みだ。ファイルシステム上に秘密鍵を配置する必要がなく、全ての端末で同期される。
筆者は以前より利用しており、今回の対応にあたっても継続して利用可能であることは必須要件だった。

使用するSSH鍵

おおまかに下記が必要になる。

  • ssh接続用鍵ペア
    • ${※x社目接続用公開鍵パス.pub} などと公開鍵パスを指す
  • commit署名用鍵ペア
    • ${※x社目署名用公開鍵パス.pub} などと公開鍵パスを指す

鍵ペア(秘密鍵)は1Passwordで管理されている必要がある他、公開鍵に限りファイルシステム上で配置されている必要がある。
また各ペアは設定する会社毎に必要となるが、ポリシー上問題ないならば、接続に用いる鍵ペアと署名用鍵ペアは同一のものでも構わない。

ssh_config

macOSにおいて1Password SSH Agentを利用する場合、通常このように設定されている。

Host *
  # 具体的には1Password側の指定に従うこと
  IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

同一ホスト、今回の場合は同じgithub.comに対する鍵を切り替えるわけだが、上記の後続行へ下記の要領で書き足すのが一般的だ。

Host mycompanygithub
  HostName github.com
  User git
  IdentityFile "${※1社目接続用公開鍵パス.pub}"
  IdentitiesOnly yes

Host customergithub
  HostName github.com
  User git
  IdentityFile "${※2社目接続用公開鍵パス.pub}"
  IdentitiesOnly yes

上記で設定した各公開鍵は、どちらも1Password内に保存されている必要がある。IdentityFileで指定した公開鍵と対応したものが1Password SSH Agentを介し選定されるといった仕組みだ。

これで実際に期待する認証がされるかは下記のように確認するとよいだろう。

ssh -vT git@mycompanygithub
# ...
# debug1: $HOME/.ssh/config line 1: Applying options for *
# debug1: $HOME/.ssh/config line 4: Applying options for mycompanygithub
# ...
# debug1: identity file ${※1社目接続用公開鍵パス.pub} type 3
# ...
# debug1: Will attempt key: ${※1社目接続用公開鍵パス.pub} ED25519 SHA256:**** explicit agent
# debug1: Offering public key: ${※1社目接続用公開鍵パス.pub} ED25519 SHA256:mGpOwrSDzlABPDesveDRiwcbqLZR72vvq/gNzYJZCuA explicit agent
# debug1: Server accepts key: ${※1社目接続用公開鍵パス.pub} ED25519 SHA256:**** explicit agent
# ...
# Authenticated to github.com ([**:****::****:****]:22) using "publickey".
# ...
# Hi ****! You've successfully authenticated, but GitHub does not provide shell access.
# ...

以後、clone時は下記の要領で行う。
なおここではわかりやすいよう GIT_SSH_COMMAND で先ほど同様のデバッグログ取得をしている。

GIT_SSH_COMMAND='ssh -v' git clone git@mycompanygithub:***/***.git
# ...
# debug1: $HOME/.ssh/config line 1: Applying options for *
# debug1: $HOME/.ssh/config line 4: Applying options for mycompanygithub
# ...
# debug1: Will attempt key: ${※1社目接続用公開鍵パス.pub} ED25519 SHA256:*** explicit agent
# ...
# Resolving deltas: 100% (***/***), done.

Git設定の最適化

認証は上記で設定完了として、続いてGit自体の設定も切り替えることが望ましいだろう。通常 ~/.gitconfigは、下記のようになっている。

[gpg]
	format = ssh

[gpg "ssh"]
	# 具体的には1Password側の指定に従うこと
	program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign"

[commit]
	gpgsign = true

これへ下記の要領で書き足す。includeIfhasconfigなどを利用する。
前者はGit 2.34、後者はGit 2.36から利用できる。

[includeIf "hasconfig:remote.*.url:git@mycompanygithub:*/*.git"]
	path = ~/.gitconfigs/mycompanygithub/.gitconfig

[includeIf "hasconfig:remote.*.url:git@customergithub:*/*.git"]
	path = ~/.gitconfigs/customergithub/.gitconfig

それぞれ ~/.gitconfigs/*/.gitconfig は下記の要領だ。allowedSignersFileなどを使う。

[user]
	email = ${※各社用Eメールアドレス}
	signingkey = ${※各社署名用公開鍵パス.pub}

[gpg "ssh"]
	allowedSignersFile = ~/.gitconfigs/${※各社識別子}/allowed_signers

実際の ~/.gitconfigs/*/allowed_signers は、各社repo内で下記の要領で作る。

echo "$(git config user.email) $(cat ${※各社署名用公開鍵パス.pub})" >> ~/.gitconfigs/${※各社識別子}/allowed_signers

動作確認は下記の要領で行う。

cd ${※1社目repoのpath}
git config --show-origin --show-scope user.signingkey
# global	file:$HOME/.gitconfigs/mycompanygithub/.gitconfig	${※1社目署名用公開鍵パス.pub}
cd ${※2社目repoのpath}
git config --show-origin --show-scope user.signingkey
# global	file:$HOME/.gitconfigs/customergithub/.gitconfig	${※2社目署名用公開鍵パス.pub}

補足

なおGitHubの場合、新規のアカウントが特定条件下でflaggedになり、commitの署名設定が正しくてもUnverified表示となってしまう。
flaggedなアカウントは他ユーザからプロフィールを参照した際に404表示となる為、チケットを発行するなどし解除してもらう必要がある。

公開: