如何配置 SSH 密钥认证?密钥认证相比密码认证有哪些优势?
SSH 密钥认证基于非对称加密,客户端持有私钥、服务器持有公钥,登录时通过加密挑战完成身份验证,无需传输密码。相比密码认证,密钥认证抗暴力破解、免输入密码、可精细控制权限,是服务器安全运维的基本要求。
密钥类型怎么选
主流密钥算法对比:
| 算法 | 密钥长度 | 安全性 | 性能 | 推荐度 |
|---|---|---|---|---|
| ED25519 | 256 bit | 极高 | 最快 | 首选 |
| ECDSA | 256 bit | 高 | 快 | 可用 |
| RSA | 4096 bit | 高 | 慢 | 兼容性场景 |
ED25519 基于 Curve25519 椭圆曲线,密钥短、签名快、抗侧信道攻击,是当前首选。RSA 4096 仅在需要兼容老旧系统时使用。
生成密钥对
bash# 生成 ED25519 密钥(推荐) ssh-keygen -t ed25519 -C "user@example.com" # 生成 RSA 4096 密钥(兼容旧系统) ssh-keygen -t rsa -b 4096 -C "user@example.com" # 指定密钥文件名 ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -C "ci/deploy" # 生成带硬件绑定的 FIDO2 密钥(需要 YubiKey 等设备) ssh-keygen -t ed25519-sk -C "user@example.com"
生成后会产生两个文件:
- 私钥(
~/.ssh/id_ed25519):绝对不能泄露,等同于你的身份凭证 - 公钥(
~/.ssh/id_ed25519.pub):可以公开,上传到目标服务器
私钥建议设置 passphrase,即使私钥被盗,攻击者也无法直接使用。
配置服务器端密钥登录
第一步:复制公钥到服务器
bash# 方法一:ssh-copy-id(最简单) ssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostname # 方法二:手动追加(目标机器没有 ssh-copy-id 时) cat ~/.ssh/id_ed25519.pub | ssh user@hostname \ "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
第二步:确认服务器 SSH 配置
编辑服务器上的 /etc/ssh/sshd_config:
bash# 启用公钥认证 PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys # 确认密钥登录成功后,再禁用密码认证 PasswordAuthentication no
修改后重启服务:
bash# Ubuntu/Debian sudo systemctl restart sshd # CentOS/RHEL sudo systemctl restart sshd
注意:先测试密钥登录成功,再禁用密码认证,否则可能锁死自己。
第三步:设置文件权限
权限不对是密钥登录失败最常见的原因:
bashchmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod 600 ~/.ssh/id_ed25519 # 私钥 chmod 644 ~/.ssh/id_ed25519.pub # 公钥
密钥认证比密码认证强在哪
抗暴力破解:密码可被字典攻击逐个尝试,而 256 bit 的 ED25519 私钥暴力破解概率在计算上不可能。一次暴力尝试的代价相差约 2^128 倍。
零密码传输:密码认证每次登录都要把密码发送到服务器,存在中间人截获风险。密钥认证只传输加密签名,私钥永不离开本地。
免交互登录:配合 ssh-agent 或无 passphrase 的密钥,可实现自动化部署、定时备份、CI/CD 流水线免密操作,密码认证做不到。
细粒度权限控制:在 authorized_keys 中可限制单个密钥的权限:
bash# 限制只能执行 git 操作 command="/usr/bin/git-shell" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... # 限制来源 IP from="10.0.0.0/8" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... # 禁用端口转发和 X11 no-port-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... # 组合限制:只允许从内网 SCP 文件 command="/usr/libexec/openssh/sftp-server",from="10.0.0.0/8",no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
多因素叠加:密钥本身是「你有的」,加上 passphrase 就是「你知道的」,再加 FIDO2 硬件密钥就是「你有的物理设备」,三因素认证也轻松实现。
ssh-agent 管理多个密钥
管理多台服务器或多个 Git 平台时,需要不同的密钥:
bash# 启动 agent eval "$(ssh-agent -s)" # 添加密钥(会提示输入 passphrase) ssh-add ~/.ssh/id_ed25519 ssh-add ~/.ssh/deploy_key # 查看已加载的密钥 ssh-add -l # 删除所有密钥 ssh-add -D
配置 ~/.ssh/config 让不同主机使用不同密钥:
bashHost github.com IdentityFile ~/.ssh/id_ed25519 User git Host production-server IdentityFile ~/.ssh/deploy_key User deploy Port 2222 Host jump-server IdentityFile ~/.ssh/id_ed25519 ProxyJump none Host internal-* ProxyJump jump-server IdentityFile ~/.ssh/id_ed25519
常见排错
密钥登录失败时,按以下顺序排查:
1. 用 verbose 模式看详细日志
bashssh -vvv user@hostname
重点看 Offering public key 和 Server accepts key 两行。
2. 检查权限
bash# 客户端 ls -la ~/.ssh/ # 私钥必须是 600,目录必须是 700 # 服务器端 ls -la ~/.ssh/ ~/.ssh/authorized_keys # authorized_keys 必须 600,~/.ssh 必须 700
3. 检查服务器端日志
bash# 查看 SSH 服务日志 sudo journalctl -u sshd --since "10 minutes ago" # 或 sudo tail -f /var/log/auth.log
常见错误原因:
| 现象 | 原因 | 解决 |
|---|---|---|
| Permission denied | authorized_keys 权限 644 | chmod 600 |
| Permission denied | .ssh 目录权限 755 | chmod 700 |
| Permission denied | 家目录被组可写 | chmod 750 ~ |
| Connection refused | sshd 未运行 | systemctl start sshd |
| 密钥不被接受 | 公钥内容被截断/换行 | 重新复制 |
| SELinux 阻止 | 文件安全上下文不对 | restorecon -Rv ~/.ssh |
安全加固清单
- 使用 ED25519 或 RSA 4096,不用 RSA 2048 及以下
- 私钥设置 passphrase,用 ssh-agent 避免反复输入
- 服务器端禁用密码认证:
PasswordAuthentication no - 禁用 root 远程登录:
PermitRootLogin no或prohibit-password - 限制 SSH 端口,不用默认 22
- 定期轮换密钥,移除 authorized_keys 中的旧公钥
- 敏感服务器使用 FIDO2 硬件密钥(
ed25519-sk) - 配置 fail2ban 防止扫描探测
- 审计 SSH 登录日志,关注异常 IP