SSH 与密钥认证
原始素材:
2-开发环境与工具/2.06-ssh-authentication.md
这篇解决什么问题
你可能遇到过这些场景:
git push时反复要求输入用户名和密码。- 连接服务器时报
Permission denied (publickey)。 - 不知道
id_rsa、id_ed25519、.pub分别是什么。 - 听说要把「公钥」放到 GitHub 或服务器,但不确定哪个能给别人、哪个必须保密。
SSH 密钥认证要解决的核心问题是:既不要每次输入密码,又不要把密码或私钥发送到网络上。
密码登录 vs 密钥登录
| 方式 | 过程 | 风险 / 特点 |
|---|---|---|
| 密码登录 | 每次输入用户名和密码,服务器校验密码 | 密码可能被撞库、钓鱼、暴力破解;使用体验差 |
| 密钥登录 | 本地私钥证明身份,服务器用公钥验证 | 私钥不离开本机,安全性和便利性更好 |
一句话理解:
- 密码登录:把密码发过去,让对方核对。
- 密钥登录:证明「我有对应私钥」,但不把私钥给对方看。
SSH 密钥认证的核心流程
SSH 密钥认证基于非对称加密。你会生成一对密钥:
- 私钥:保存在自己电脑上,绝不能泄露。
- 公钥:可以放到 GitHub、GitLab、服务器的
authorized_keys中。
认证流程可以简化为:
本机发起 SSH 连接
-> 服务器发现这个用户配置了公钥
-> 服务器发起挑战
-> 本机用私钥对挑战签名
-> 服务器用公钥验证签名
-> 验证通过,允许登录
重点:私钥不会被发送到服务器。
公钥和私钥
| 项目 | 私钥 Private Key | 公钥 Public Key |
|---|---|---|
| 常见文件 | ~/.ssh/id_ed25519 |
~/.ssh/id_ed25519.pub |
| 保存位置 | 自己电脑 | GitHub、GitLab、服务器 |
| 是否能给别人 | 绝对不能 | 可以公开 |
| 作用 | 签名,证明身份 | 验签,确认身份 |
| 类比 | 钥匙 | 锁 |
如果私钥泄露,应立即:
- 从 GitHub / GitLab / 服务器删除对应公钥。
- 重新生成新的密钥对。
- 检查是否有异常登录或异常 Git 操作。
常见密钥类型
| 类型 | 生成命令 | 推荐度 | 说明 |
|---|---|---|---|
| Ed25519 | ssh-keygen -t ed25519 |
推荐 | 现代、速度快、安全性好,优先使用 |
| RSA | ssh-keygen -t rsa -b 4096 |
可用 | 兼容性强,适合老系统 |
| ECDSA | ssh-keygen -t ecdsa |
一般不推荐 | 实际使用中优先级较低 |
日常开发推荐 Ed25519:
ssh-keygen -t ed25519 -C "your@email.com"
如果目标服务器太老,不支持 Ed25519,再考虑 RSA 4096:
ssh-keygen -t rsa -b 4096 -C "your@email.com"
生成 SSH 密钥
执行:
ssh-keygen -t ed25519 -C "your@email.com"
常见提示:
| 提示 | 建议 |
|---|---|
| 保存路径 | 默认 ~/.ssh/id_ed25519 通常即可 |
| passphrase | 可以设置,用于给私钥再加一层保护 |
| 覆盖已有文件 | 谨慎,可能影响现有 GitHub 或服务器登录 |
生成后通常会得到:
~/.ssh/id_ed25519 # 私钥,不能泄露
~/.ssh/id_ed25519.pub # 公钥,可以添加到服务端
查看公钥:
cat ~/.ssh/id_ed25519.pub
添加公钥到 GitHub
复制公钥内容。
macOS:
pbcopy < ~/.ssh/id_ed25519.pub
Linux:
xclip -sel clip < ~/.ssh/id_ed25519.pub
如果没有剪贴板工具,也可以直接输出后手动复制:
cat ~/.ssh/id_ed25519.pub
然后在 GitHub 中添加:
GitHub
-> Settings
-> SSH and GPG keys
-> New SSH key
-> 粘贴公钥
测试连接:
ssh -T git@github.com
成功时通常会看到类似:
Hi username! You've successfully authenticated...
添加公钥到服务器
推荐使用 ssh-copy-id:
ssh-copy-id user@your-server
它会把本机公钥追加到服务器用户的:
~/.ssh/authorized_keys
如果没有 ssh-copy-id,可以手动追加:
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
服务器侧常见权限要求:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
如果权限太宽,SSH 可能拒绝使用这些文件。
SSH Config:给连接起别名
如果你经常连接服务器,不要每次都写长命令:
ssh -i ~/.ssh/id_ed25519 deploy@192.168.1.100
可以在 ~/.ssh/config 中配置:
Host dev
HostName 192.168.1.100
User deploy
IdentityFile ~/.ssh/id_ed25519
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
之后只需要:
ssh dev
常用字段:
| 字段 | 说明 |
|---|---|
Host |
别名,可以自定义 |
HostName |
真实主机名或 IP |
User |
登录用户名 |
Port |
SSH 端口,默认 22 |
IdentityFile |
指定私钥路径 |
ProxyJump |
跳板机配置 |
带跳板机的例子:
Host prod
HostName 10.0.0.12
User deploy
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion
Host bastion
HostName 203.0.113.10
User jump
IdentityFile ~/.ssh/id_ed25519
Git 使用 SSH 地址
如果 GitHub 已添加 SSH 公钥,但 git push 仍然要求输入密码,常见原因是仓库 remote 还是 HTTPS。
查看 remote:
git remote -v
HTTPS 地址长这样:
https://github.com/user/repo.git
SSH 地址长这样:
git@github.com:user/repo.git
切换为 SSH:
git remote set-url origin git@github.com:user/repo.git
再测试:
git pull
git push
私钥权限
如果看到:
WARNING: UNPROTECTED PRIVATE KEY FILE!
说明私钥文件权限太宽。修复:
chmod 600 ~/.ssh/id_ed25519
chmod 700 ~/.ssh
含义:
| 权限 | 用途 |
|---|---|
700 ~/.ssh |
只有当前用户能进入 .ssh 目录 |
600 私钥 |
只有当前用户能读写私钥 |
644 公钥 |
公钥可读,通常问题不大 |
常见问题排查
| 问题 | 常见原因 | 解决方案 |
|---|---|---|
Permission denied (publickey) |
公钥没放到服务器或 GitHub | 添加公钥,检查用户名和 remote 地址 |
WARNING: UNPROTECTED PRIVATE KEY FILE |
私钥权限太宽 | chmod 600 ~/.ssh/id_ed25519 |
Could not resolve hostname |
~/.ssh/config 的 HostName 写错 |
检查别名、缩进、真实主机名 |
| GitHub 仍要密码 | 使用了 HTTPS remote | 改成 git@github.com:user/repo.git |
Connection refused |
服务器 SSH 服务没开或端口错 | 检查端口、防火墙、sshd 状态 |
Operation timed out |
网络不通或安全组拦截 | 检查 VPN、路由、安全组、防火墙 |
| 多个密钥选错 | SSH 自动尝试了错误私钥 | 在 ~/.ssh/config 指定 IdentityFile |
调试 SSH 连接
使用 -v 查看详细连接过程:
ssh -v user@server
更详细:
ssh -vvv user@server
调试时重点看:
- 实际连接的主机和端口。
- 尝试了哪些私钥。
- 服务器是否接受了某个公钥。
- 最终失败原因是认证失败、网络失败,还是主机名解析失败。
安全建议
- 私钥不要发给任何人,也不要提交到 Git。
- 给不同用途使用不同密钥,例如 GitHub、公司服务器、个人服务器分开。
- 私钥建议设置 passphrase,尤其是笔记本电脑。
- 不再使用的公钥及时从 GitHub、GitLab、服务器删除。
- 服务器尽量关闭密码登录,只允许密钥登录。
- 生产服务器限制 SSH 来源 IP,或通过 VPN / 跳板机访问。
- 定期检查
~/.ssh/authorized_keys,删除未知公钥。
小结
- SSH 密钥认证比密码更安全,因为私钥不会在网络中传输。
- 公钥可以给 GitHub、GitLab、服务器;私钥必须留在本机。
- 日常开发优先使用 Ed25519 密钥。
~/.ssh/config可以把长 SSH 命令变成短别名。- GitHub 免密推送需要同时满足:添加公钥,并使用 SSH remote。
- SSH 排错时优先看用户名、主机、端口、公钥是否添加、私钥权限和 remote 地址。