1. 闲言碎语
凌晨4点的夜空,月亮不知道躲到哪里去了。黑暗的幕布向西边消退,透过窗帘依稀能看到些许亮光。天快亮了。
近来跳槽之际,闲来无事,遂心生一念:使用 GPG 管理 SSH 密钥。
2. 方案一
以下步骤的实施前提是您已成功安装 GnuPG 相关软件(Debian 9/10均默认安装)
2.1 设置环境变量
1 2 |
export GPG_TTY=$(tty) export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) |
建议添加到配置文件中,比如 ~/.profile
或 ~/.bashrc
2.2 添加 SSH 私钥
1 2 3 |
ssh-add -c -t 3600 ~/.ssh/id_rsa # -c 每次使用的时候弹窗确认(不建议开启) # -t 设置密钥的缓存超时时间,超时之后需要再次输入密码解锁 |
执行该命令的时候需要先输入原SSH私钥的解密密码(如果存在的话),然后输入新的加密密码。
(具体的配置可参考方案二“sshcontrol”相关内容
2.3 简单测试
可通过如下方式检测是否正常工作:
1 2 3 |
gpg --export-ssh-key ${用户ID} ssh-add -l ssh-add -L |
3. 方案二
3.1 使用 pem2openpgp 转换密钥格式并导入 GPG
将 SSH 私钥转换为 OpenPGP 格式的私钥,并导入GPG,用户ID随机选取即可,最后记下新添加密钥的 Keygrip 值
1 2 3 |
apt install monkeysphere pem2openpgp ${临时ID} < .ssh/id_rsa | gpg --import gpg --with-keygrip -k ${临时ID} |
3.2 将上述密钥作为另一个用户的 subkey
1 2 3 4 5 6 7 8 |
gpg --expert --edit-key ${主帐号的ID/邮箱/KEYID} gpg --expert --edit-key {} gpg> addkey Please select what kind of key you want: ...... (13) Existing key Your selection? 13 Enter the keygrip: XXXXXXXXXXXXXXXX |
在添加key的时候,选择(13)Existing key,然后输入这个密钥的Keygrip;随后设置该密钥的用途,去掉“Sign” 和 “Encrypt”功能,设置“authenticate“功能即可。
3.3 备份私钥,删除临时用户
因为gpg在删除key的时候,需要先删除私钥,而我们刚添加的私钥同时被两个用户使用了,所以不能直接删除,需要先备份一下。
cp -r ~/.gnupg/private-keys-v1.d ~/
gpg --delete-secret-keys ${临时ID}
cp -r ~/private-keys-v1.d ~/.gnupg/
3.4 配置 SSH 认证(sshcontrol)
1)编辑 ~/.gnupg/sshcontrol 文件,添加如下数据,三个字段分别为:Keygrip(必选),缓存超时时间(秒为单位,可),Flag参数(是否每次使用时弹窗确认,仅支持参数:comfirm,可选,不建议开启)
1 2 3 4 5 6 7 8 9 10 11 12 |
# List of allowed ssh keys. Only keys present in this file are used # in the SSH protocol. The ssh-add tool may add new entries to this # file to enable them; you may also add them manually. Comment # lines, like this one, as well as empty lines are ignored. Lines do # have a certain length limit but this is not serious limitation as # the format of the entries is fixed and checked by gpg-agent. A # non-comment line starts with optional white spaces, followed by the # keygrip of the key given as 40 hex digits, optionally followed by a # caching TTL in seconds, and another optional field for arbitrary # flags. Prepend the keygrip with an '!' mark to disable it. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3600 confirm |
3.5 配置环境变量
1 2 |
export GPG_TTY=$(tty) export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) |
建议添加到配置文件中,比如 ~/.profile
或 ~/.bashrc
3.6 简单测试
可通过如下方式检测是否正常工作:
1 2 3 |
gpg --export-ssh-key ${用户ID} ssh-add -l ssh-add -L |
4. 重新导出为 ssh 私钥
(更新于 2020.02.20)
如果是方案二,则通过 gpg 命令可以看到对应的 subkey,使用如下命令导出:
(操作前请备份相关数据或文件)
1 2 3 |
gpg -K --keyid-format LONG --with-keygrip # 查看私钥列表,记下 KEYID gpg --expert --edit-key # 然后使用 passwd 命令,重置私钥密码,新密码设置为空,因为下一步的工具不支持加密的私钥导出 gpg --export-secret-keys | openpgp2ssh KEYID # 或者使用 --export-secret-subkeys |
如果是方案一,也就是 gpg 命令并看不到对应的 subkey,但是 ~/.gnupg/private-keys-v1.d/ 目录下存在相应私钥文件,文件名即为 keygrip; 参照方案二将其添加为 subkey,然后操作同上;
5. 一些思考
-
1)方案一 ssh-add 在添加SSH私钥的时候,实际上对端 gpg-agent 会自动完成格式转换工作,类似于方案二中使用 pem2openpgp 的工作;
-
2)方案一 ssh-add 添加之后的 SSH key,和用户其他私钥一样保存在了 ~/.gnupg/private-keys-v1.d/ 目录中,但是 gpg -k/-K 以及 --export-ssh-key 都是无法看到这个key的. (私钥文件名即该密钥的 keygrip,添加为subkey的时候需要填写该值);
-
3)方案一添加过程中,可以单独给 SSH key 设置加密密码,而方案二操作过程中没有加密的步骤;
-
4)两种方案主要不同在于是不是作为用户 master key 的一个 subkey,差别不大,意义仅仅在于,如果你把它放在了master key下面,就可以对其进行expire、revoke等操作。而实际上,对于SSH key,没有PKI基础设施,传输基本靠人肉操作,expire 和 revoke也就没什么意义了。 所以仅仅是当某个用户还没有SSH key,而打算使用gpg新生成一对的时候,作为subkey是有其合理性的。否则没什么必要把已有的SSH key手动添加为subkey(思考了很久之后的个人理解,如果错误,望不吝赐教)。
-
5)gpg-agent 在管理 SSH key 的时候,需要ssh密钥有密码,且在配置了合适的sshcontrol参数之后,解锁这个key的时候会弹窗确认。 有个问题,SSH远程登录的情况下需要使用ssh私钥(比如继续登录另一台机器),这个弹窗会被显示到远程机器的图形界面上,因此远程似乎无法使用到这个key。 在这一点上,ssh-agent 会在文本模式下提示你输入密码,这很人性化了(待调研)