说实话,我看到好几个技术交流群里都在转“SSH密钥过期”这个话题,点进去一看,大部分人都把问题理解窄了。很多人一看到“过期”两个字,就以为是密钥本身有个保质期,到时间自动失效。这个说法对,但也不全对——要是你用的是最普通的SSH Key,它本身确实没有内置的失效时间;但你偏偏连不上服务器了、没法推送代码了,那这个“过期”的感觉又从哪来?
这就要说到真实的坑了。过去这段时间,我前前后后帮人排查了十几个类似的问题,有的是GitLab代码推不上去,有的是Gerrit审查系统登不进去,还有的是自己云服务器突然要密码了。原因五花八门,但表象都指向同一件事——密钥不“认”了。所以这篇东西我不想只讲一个点,而是想顺着“密钥过期”这个由头,把从生成、配置、验收到排查的整条链路都过一遍。你踩过的坑、还没踩的坑,我尽量都写到。
1. 先搞清楚:SSH密钥到底会不会过期
1.1 普通SSH密钥的“有效期”是个伪命题
先说结论:你自己执行ssh-keygen生成的那对密钥,私钥和公钥文件里是没有“有效期”这个字段的。只要私钥文件不丢、不被覆盖、不被删除,理论上十年后它还是同一把钥匙。
那为什么大家会碰到类似“密钥过期”的报错?最常见的情形是服务端拒绝了你,而客户端又没给出足够明确的提示。比如你推送代码到GitLab时,跳出这么一串:
code复制git@gitserver: Permission denied (publickey).
fatal: Could not read from remote repository.
看到这个,第一反应是密钥坏了、被吊销了、过期了。其实这里的Permission denied (publickey)只说明一个问题:服务端在你的公钥列表里,找不到能匹配你这次连接所用的私钥。也就是说,这不叫过期,叫“不被识别”。
为什么不被识别?要么是公钥压根没传到服务器上,要么是传错了账户,要么是你本机SSH登录时选错了私钥文件,要么是客户端软件升级后默认算法变了、不再加载旧的密钥类型。
1.2 新式SSH证书才真正“自带过期时间”
如果你在大型公司或严格管理的基础设施团队待过,可能接触过另一种东西——SSH Certificate,也就是由CA签发的SSH证书。这种证书里面确实包含valid-from和valid-to时间字段,到点就失效,没有任何商量余地。这是为了满足安全合规要求,强制员工定期轮换身份凭证。
现在不少云厂商、内部堡垒机系统都支持这种证书登录方式。当CA签发的证书过期时,你连上去就会看到:
code复制Certificate invalid: expired
或者服务端日志里出现类似“key is not valid”的记录。这种情况下的“过期”才是真正意义上的过期。
但日常开发者和中小团队用得最多的,还是GitLab、Gerrit、GitHub或者自建Git服务器上的普通SSH Key。所以这篇内容的重点,也放在普通密钥的“准过期”问题排查上。当你把所有可能性都排掉之后,如果确实用了证书体系,再单独确认CA那边的时间策略也不迟。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 自查秘钥状态:先确认问题出在本地还是远端
2.1 检查本地私钥是否还在、是否被软件加载
遇到连不上的情况,我的习惯是先在本机做一轮快速体检,不要一上来就重新生成密钥。重新生成密钥意味着你要把新公钥重新配到所有服务器上,成本很高。排查顺序很关键。
第一步,确认私钥文件还在:
bash复制ls -l ~/.ssh/
正常情况下,这里面会有id_ed25519和id_ed25519.pub这样的成对文件,也可能是id_rsa和id_rsa.pub。如果你看到私钥文件没了,但.pub文件还在,那说明私钥确实丢了。这种情况下别犹豫,只能重新生成一对新密钥,然后把新公钥灌到所有目标服务器上。
第二步,用ssh-add -l查看当前会话中SSH Agent加载了哪些私钥:
bash复制ssh-add -l
如果你之前用ssh-add ~/.ssh/id_ed25519把私钥加进过Agent,重启电脑或重启终端后Agent缓存会被清空。这时候你去连服务器,客户端可能找不到对应的私钥,看起来就像“密钥失效了”。但其实你把密钥重新加一遍就好:
bash复制eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed255
