前阵子重读了一篇旧文A Git Horror Story: Repository Integrity With Signed Commits,感觉还是有必要通过GPG签名来提交的来源可信。于是抽空重新配置了本地的开发环境,把GPG-sign补上了。

准备工作

Keybase 注册账号。 使用Keybase的原因是可以在网站上托管密钥(加密过),方便迁移

工具安装(HomeBrew)

1
2
$ brew install gnupg
$ brew cask install gpg-suite keybase

环境配置

使用keybase创建GPG密钥

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ keybase pgp gen --multi

Enter your real name, which will be publicly visible in your new key: Josta Yee
Enter a public email address for your key: [email protected]
Enter another email address (or <enter> when done):
Push an encrypted copy of your new secret key to the Keybase.io server? [Y/n] Y
When exporting to the GnuPG keychain, encrypt private keys with a passphrase? [Y/n] Y
▶ INFO PGP User ID: Josta Yee <[email protected]> [primary]
▶ INFO Generating primary key (4096 bits)
▶ INFO Generating encryption subkey (4096 bits)
▶ INFO Generated new PGP key:
▶ INFO   user: Josta Yee <[email protected]>
▶ INFO   4096-bit RSA key, ID 438BDA794F609085, created 2018-08-18
▶ INFO Exported new key to the local GPG keychain

填入想要签名的user.name/user.email,一路回车确认完成。

修改Git配置文件

1
2
3
4
5
6
7
8
$ gpg --list-secret-keys --keyid-format LONG

/Users/yee/.gnupg/pubring.kbx
-----------------------------
sec   rsa4096/438B********9085 2018-08-18 [SC] [expires: 2034-08-14]
      64D89F4FE50C****************DA794F609085
uid                 [ unknown] Josta Yee <[email protected]>
ssb   rsa4096/2E16********79D7 2018-08-18 [E] [expires: 2034-08-14]

把输出的sec rsa4096/后面一段加入~/.gitconfig

1
2
3
$ git config --global user.signingkey 438B********9085
$ git config --global commit.gpgsign true
$ git config --global gpg.program $(which gpg)

顺便添加gnupg的配置文件:

1
2
$ echo "use-agent\nno-emit-version\ndefault-key 438B********9085" > ~/.gnupg/gpg.conf
$ echo "use-standard-socket\ndefault-cache-ttl 600\nmax-cache-ttl 7200" > ~/.gnupg/gpg-agent.conf

接着将生成的key公钥导入平台

  • 获取key id
1
2
3
4
5
6
$ keybase pgp list

Keybase Key ID:  010198df77b67748078160a4************************90b658de038d24d98d680a
PGP Fingerprint: 64D8 9F4F E50C **** **** **** **** DA79 4F60 9085
PGP Identities:
   Josta Yee <[email protected]>
  • 导出公钥(使用Keybase key ID的前16位字符即可)
1
$ keybase pgp export -q 010198df77b67748 | pbcopy

为了能让tty操作时正确弹窗提示输入密码,还需要在shell配置里面设置GPG_TTY环境变量:

1
export GPG_TTY=$(tty)

这样在git commit时会看到:

1
2
3
4
5
6
7
8
9
│ Please enter the passphrase to unlock the OpenPGP secret key:  │
│ "Josta Yee <[email protected]>"                                    │
│ 4096-bit RSA key, ID EF9AAFDEF0AA499C,                         │
│ created 2018-08-13.                                            │
│                                                                │
│                                                                │
│ Passphrase: __________________________________________________ │
│                                                                │
│         <OK>                                    <Cancel>       │

输入密码验证通过后就成功了:

1
2
[master 90e1fce] ok
 1 file changed, 1 insertion(+)

密码会缓存一段时间,不用每次都重复输入。

然后测试一下push,最后就能在网页上看到被认证的绿色Verified提示了。 verified commits

多账号支持

工作开发使用的公司账号,现在是通过使用Git config includeIf区分,这里同样可以针对不用用户签名,只需新生成一套密钥,在gitconfig-work加入即可,如下:

1
2
3
4
[user]
  name = mywork
  email = [email protected]
  signingkey = D7BF********F0D5

新设备导入

添加新设备时导入之前生成的密钥非常简单,登录keybase账号之后将需要的公私钥分别导入至本地PGP keychain即可:

1
2
3
4
5
6
$ keybase pgp export -q 010198df77b67748 | gpg --import
$ keybase pgp export -s -q 010198df77b67748078160a4************************90b658de038d24d98d680a | gpg --import --allow-secret-key-import

# 检查导入结果
$ gpg --list-keys
$ gpg --list-secret-keys

注意从keybase导出私钥时keyID不可以使用前16位简写,否则可能报 ERROR No matching keys found 错误而失败。

备注

  • Git之父Linus Torvalds本人并不赞成signed commits,具体可以参见当年的邮件列表
  • GitHub只识别第一个登记邮箱,所以在生成时不要填写多个email比较好。
  • 如果提交失败,可以使用echo "test" | gpg --clearsign检查是否能正确签名,还可以设置GIT_TRACE=1打开Git操作的跟踪日志作调试。

参考

History

VersionActionTime
1.0Initial commitAug 18, 2018
1.1How to import keys after adding a new deviceDec 25, 2018