文章目录
- 前言
- 开发环境
- 单个SSH密钥
- 1.1. 生成SSH密钥
- 1.2. 添加SSH密钥
- 1.3. 测试SSH连接
- 2.1. 简化密钥密码输入
- 多个SSH密钥
- 1.1. 生成/添加/测试SSH密钥
- 2.1. 简化密钥密码输入
- 无密码密钥
- 补充内容
- 最后
前言
有一个SSH
密钥跟了我很多年,更换电脑也不曾更换它。它不需要额外输入密码就能用,我将它的公钥用在了诸多平台。虽然很方便,但是安全性差(指没有密码)和匿名性差(指同一公钥在不同平台可能被关联)。
于是,计划在保留已有SSH
密钥的情况下,先新创建一个SSH
密钥专门用于GitHub
,并加上密码增加安全性,后续再逐步为其他平台创建。在实际操作过程中,遇到了一些问题并进行研究,在此记录一番,希望对你有所帮助。
注意,以下内容均是以GitHub
使用SSH
连接为例,分别讨论单个或多个SSH
密钥的使用等问题。可能存在不完善或少许错误,欢迎留言评论补充或指正。
开发环境
- MacOS: 14.3.1
- SSH: OpenSSH_9.4p1
单个SSH密钥
如果不考虑匿名性,每台设备只维护单个SSH
密钥用于各个平台是很轻松的,加上密码安全性也有一定的保障。GitHub
使用SSH
进行连接的步骤如下:
1.1. 生成SSH密钥
- 执行密钥创建命令
# 这是使用RSA算法生成
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 现在一般推荐使用安全性更高的Ed25519算法生成
ssh-keygen -t ed25519 -C "your_email@example.com"
your_email@example.com
一般是GitHub
上账号的电子邮件地址(来自GitHub
官方文档的说法)。不过,这有个问题,一台设备上如果只管理一个SSH
密钥,然后不同平台上的电子邮件地址又不一样,那该填什么?
先不管GitHub
的说法,我们可以通过使用手册命令看看-C
选项的含义:
man ssh-keygen
输出很长,这里只展示关于-C
及-c
选项的内容(补充:-t
选项是指定密钥类型):
...
-C comment
Provides a new comment.
-c Requests changing the comment in the private and public key
files. The program will prompt for the file containing the
private keys, for the passphrase if the key has one, and for the
new comment.
...
可见-C
选项后面跟的只是注释,方便你标识这个密钥(标识用途或所有者等)。实测,直接填your_email@example.com
也一切正常!而且这个注释是可以通过-c
选项修改的,修改命令参考如下:
ssh-keygen -c -f ~/.ssh/id_ed25519
实测能修改成功,并且不需要更新已经添加到GitHub
的公钥,注释信息并不会影响身份验证。所以,填什么请随意。
- 设置密钥存放路径
# RSA算法生成
Enter file in which to save the key (/Users/xxx/.ssh/id_rsa):
# Ed25519算法生成
Enter file in which to save the key (/Users/xxx/.ssh/id_ed25519):
建议直接按Enter
键使用它已经给出的默认文件路径,具体原因请看后面无密码密钥部分的内容。
- 设置密钥密码
Enter passphrase (empty for no passphrase):
如果不使用密码可以直接按Enter
键,不过建议使用密码。生成密钥成功后,可以参考以下命令新增/修改/删除密码:
ssh-keygen -p -f ~/.ssh/id_ed25519
- 生成密钥成功
Your identification has been saved in /Users/xxx/.ssh/id_rsa(或id_ed25519)
Your public key has been saved in /Users/xxx/.ssh/id_rsa.pub(或id_ed25519.pub)
The key fingerprint is: xxx your_email@example.com
The key's randomart image is: xxx
参考文档:
- GitHub - 生成新SSH密钥
1.2. 添加SSH密钥
打开SSH and GPG keys页面,如果没有登录请先登录。点击[New SSH key]按钮添加SSH
密钥:
Title
:给密钥设置描述性标签,可以用于区分设备。当某个设备的私钥泄漏时,方便快速找到该设备的SSH
密钥并删除Key type
:密钥类型,分为Authentication Key
(身份验证)和Signing Key
(提交签名),使用默认的身份验证类型即可Key
:前面生成的公钥,可以通过以下命令将公钥复制到剪贴板,也可以找到公钥文件(.pub
扩展名)用文本程序打开复制
# 复制RSA算法生成的密钥
pbcopy < ~/.ssh/id_rsa.pub
# 复制Ed25519算法生成的密钥
pbcopy < ~/.ssh/id_ed25519.pub
由于添加密钥是敏感操作,GitHub
一般会让你再次验证身份,参考Sudo 模式。
参考文档:
- GitHub - 向你的帐户添加新的SSH密钥
1.3. 测试SSH连接
通过执行以下命令测试:
ssh -T git@github.com
一般会得到这样的输出:
The authenticity of host 'github.com (20.205.243.166)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
其中SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
是服务器的公钥指纹,用于验证服务器的身份。GitHub的SSH密钥指纹:
SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s
(RSA)
SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM
(ECDSA)
SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
(Ed25519)
确认公钥匹配后,输入yes
完成身份验证,会自动在~/.ssh/known_hosts
文件中保存已验证服务器信息,后续无需再次验证,除非服务器信息有变化。
如果密钥有密码,需要输入密码完成连接测试。
参考文档:
- GitHub - 向你的帐户添加新的SSH密钥
2.1. 简化密钥密码输入
如果你的SSH
密钥有设置密码,那么你会发现每次使用(例如执行git pull
命令)都需要输入一遍密码,相当麻烦。那么有什么办法可以解决这个问题呢?
这就不得不提到SSH
代理,将密钥添加到代理,只需要输一次密码,后续无需重复输入密码。先在~/.ssh
路径下创建config
文件(如果该文件不存在):
touch ~/.ssh/config
然后往里面添加配置:
Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
AddKeysToAgent
:将密钥加入代理UseKeychain
:将密码存储在钥匙串IdentityFile
:指定密钥文件路径
配置后,只需要输入一次密码,密码会自动保存到钥匙串,打开钥匙串应用搜索SSH
关键词可以找到存储记录。通过以下命令可以查看已经添加到SSH
代理中的密钥:
ssh-add -l
当重启电脑后(也可以通过killall ssh-agent
命令终止代理,在需要时会自动重启)马上查看SSH
代理中的密钥,你会发现没有加载任何密钥:
The agent has no identities.
这时使用SSH
连接(例如执行git pull
命令),会自动添加密钥,也无需再输入密码。
关于配置中的Host
,这里引出另一个问题,现在只维护单个密钥用于多个平台,按前面的配置,只有连接GitHub
时能简化密码输入,其他平台还是每次都需要输入密码。
这很好解决,在config
文件中参考前面的配置修改Host
给其他平台也增加配置即可。需要注意一点,有些平台的Host
可能类似这样的git.github.com
,这时你要么完全按照这个配置,要么使用通配符*.github.com
。
如果平台多了,配置也挺麻烦的,本来只维护单个密钥就为了省事,那还有没有更省事的方法呢?肯定是有的,参考如下配置:
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
参考文档:
- GitHub - 将SSH密钥添加到ssh-agent
多个SSH密钥
1.1. 生成/添加/测试SSH密钥
参考前面单个SSH
密钥的生成/添加/测试,除了设置密钥存放路径时需要重新命名区分已有的密钥文件外,操作基本一样。
我一般按照这个格式id_aaa.bbb
命名,aaa
是密钥类型(例如ed25519
),bbb
是平台标识(例如github
)。按自己喜好命名,方便自己标识就行。
2.1. 简化密钥密码输入
参考前面单个SSH
密钥的简化密码输入,可以针对不同平台配置不同的密钥文件:
Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519.github
Host xxx.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa.xxx
或者更简单点(不过都维护多个密钥了,应该很少这么做了吧):
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_rsa
如果按照上方示例中的配置,会根据先后顺序匹配。例如id_ed25519
密钥会被优先匹配,只有当匹配失败或密码错误,才会继续往下匹配。
无密码密钥
前面着重讲设有密码的密钥,那如果密钥不设置密码还需要配置吗?
这里先引出一个默认密钥文件的说法,默认密钥文件指使用默认名称命名并放在默认路径下的密钥。默认路径和默认名称分别指:
- 默认路径:
~/.ssh
- 默认名称:
id_dsa
|id_ecdsa
|id_ecdsa_sk
|id_ed25519
|id_ed25519_sk
|id_rsa
进而引出:
- 对于单个无密码密钥,只要属于默认密钥文件,
SSH
会自动添加,无需再额外配置 - 对于多个无密码密钥,不属于默认密钥文件的需要在
config
文件中配置,参考配置如下:
Host github.com
IdentityFile ~/.ssh/id_ed25519.github
或许你会疑问,默认密钥文件的说法是怎么来的?
在已有密钥的情况下创建新密钥时,我发现自定义命名的密钥无法直接使用,同时将密钥名称改为默认名称后又可以了,所以合理猜测存在一些默认密钥文件会被SSH
自动添加(无论密钥是否有密码,有密码的密钥不配置也能正常使用,只是需要输入密码)。
关于猜测的具体验证过程请看续篇:GitHub - 使用SSH进行连接(续)。
补充内容
除了通过配置config
文件简化密码输入,还可以通过以下方法。
在~/.bash_profile
或~/.zshrc
文件末尾加上:
if ! ssh-add -l | grep -q "your_email@example.com"; then
ssh-add --apple-use-keychain ~/.ssh/id_ed25519.github
fi
其中your_email@example.com
是创建密钥时的注释(参考前面的密钥创建),~/.ssh/id_ed25519.github
是密钥文件路径,请根据实际情况替换。
追加内容保存后,重新打开终端或用source
命令使其生效。根据提示,首次输入密码后,后续无需再输入密码。
这个原理很简单,每当打开终端时,首先通过ssh-add -l
命令获取已经添加到SSH
代理中的密钥信息,然后根据密钥信息搜索是否包含特定注释信息,以此判断密钥是否已经被添加到SSH
代理中,最后如果没添加则通过ssh-add --apple-use-keychain
命令添加。
--apple-use-keychain
的作用是将首次输入的密码存储到钥匙串中。补充一点,以前是用-K
,现在已经被弃用。
注意,这个方法有个缺点,如果重启电脑后你没先打开终端触发自动加载密钥,那就不会加载。
例如重启电脑后,直接用Sourcetree
软件执行Git
相关操作,会报错。不过,Android Studio
是例外,猜测可能是因为它启动时也启动了shell
进程,触发了密钥加载。
简单验证一下猜测:删除钥匙串中保存的密钥密码,并且通过killall ssh-agent
命令终止代理(清除已添加的密钥),重新启动Android Studio
,随意打开一个项目,结果卡住了一会儿,还弹了警告:
Learn more
按钮指向Shell Environment Loading文章。
同时内置终端卡在密钥密码输入。结合Learn more
按钮指向的文章可知,Android Studio
果然启动了shell
进程,当遇到首次加载密钥需要输入密码时,会因为等待密码输入而卡住,直到等待超时。
最后
如果这篇文章对你有所帮助,点赞👍收藏🌟支持一下吧,谢谢~
本篇文章由@crasowas发布于CSDN。