上周组里有个同事突然在群里喊:我上午还能push代码,午休起来就Permission denied了,SSH密钥过期了吗?我过去看了一眼,.ssh目录里的文件都还在,GitLab那边Key也没有删,最后发现是他前几天重装系统时把公钥重新生成过,本地私钥和服务端公钥对不上了。
这种"SSH密钥过期"其实每天都会在团队里发生几次。大多数情况下,并不是密钥真的有过期时间,而是配置链路里某个环节悄悄变了。这篇就围绕SSH密钥失效这个场景,把密钥的生成、GitLab配置SSH密钥、Gerrit配置SSH密钥和问题定位完整过一遍,看完你大概率能自己解决团队里80%的"密钥过期"问题。
1. SSH密钥为什么会"过期"
1.1 你可能遇到了假"过期"
先说结论:SSH密钥对本身是没有过期时间这个概念的。你在终端里跑ssh-keygen生成的那一串RSA或Ed25519密钥,如果没人动它,放十年它还是同一对密钥,技术上完全能用。
那"你的SSH密钥可能已经过期了"这个说法是怎么来的?我归纳了一下,实际工作中见到的所谓过期,绝大多数是下面几种情况:
- 本地私钥文件被误删、重装系统没备份,而服务端还留着旧公钥。
- 服务端把旧的
authorized_keys记录清理掉了,比如你离职又回来、或者公司做了周期性账号审计。 - 你重新生成过密钥对,新私钥和远端GitLab或Gerrit上存的旧公钥不是配对关系。
- GitLab的管理员在后台手动撤销了你的Key,GitLab界面里显示状态正常,但实际服务端已经拒绝。
- 主机指纹变了,也就是
known_hosts里记录的服务端公钥和你当前连的那台机器对不上,SSH会直接拒绝连接。
前四种属于"身份认证对不上",最后一种其实是"伪过期",它报错方式和密钥错误非常像,但根因完全不同。后面第五节专门讲排查时怎么区分。
判断是不是"假过期",最直接的方法是看一眼SSH客户端的报错。Permission denied (publickey)是密钥认证失败,而WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED是known_hosts问题。这两种错了以后要走的排查路径完全是两条。
1.2 "真过期"的幕后原因
如果排除上面那些假象,有没有真正算得上"过期"的情况?有,但在代码托管场景里不是密钥自身过期,而是策略层面把它置为失效:
- 你在GitLab里上传的公钥虽然界面写着Active,但管理员可能开了Key过期时间限制,定期强制轮换。
- 很多公司做账号生命周期管理,员工账号被禁用后关联的SSH Key会一并失效,即使你的本地文件和服务端记录都还在。
- Gerrit这类做代码评审的平台,如果用户账号被标记为Inactive,密钥同样无法使用。
所以当你看到"密钥过期"这类话术时,建议立刻去检查的清单是:本地私钥在不在、服务端公钥在不在、账号状态正不正常、known_hosts有没有变。这四个方向覆盖了我在企业里遇到的九成以上问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从零配置一套可用的SSH密钥
2.1 生成密钥前先想清楚这3个问题
不要一上来就ssh-keygen按回车按到底。我在实际帮人排查时发现,很多问题恰恰是生成阶段埋下的。
第一个问题是选什么算法。早些年大家都用RSA 2048,现在更推荐Ed25519,速度快、安全性好而且密钥短。不过注意一点:如果你要连接的是一些比较老旧的内部系统,可能只支持RSA,那就用ssh-keygen -t rsa -b 4096。GitLab和Gerrit对Ed25519的支持都很好,所以新环境优先Ed25519。
第二个问题是给不给私钥设passphrase。设了的优点是私钥泄露后别人也难用,缺点是每次连接都要输入密码。
