CC 咖啡猫的工作空间 Coding Space

SSH 与密钥认证

原始素材:2-开发环境与工具/2.06-ssh-authentication.md

这篇解决什么问题

你可能遇到过这些场景:

  • git push 时反复要求输入用户名和密码。
  • 连接服务器时报 Permission denied (publickey)
  • 不知道 id_rsaid_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、服务器
是否能给别人 绝对不能 可以公开
作用 签名,证明身份 验签,确认身份
类比 钥匙

如果私钥泄露,应立即:

  1. 从 GitHub / GitLab / 服务器删除对应公钥。
  2. 重新生成新的密钥对。
  3. 检查是否有异常登录或异常 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 地址。