SSH 密钥登录与 config 配置入门:从生成密钥到服务器加固
一、为什么要把密码登录换成密钥登录
如果你管理过几台云服务器,一定见过这样的场景:每天凌晨被安全组告警叫醒,登录服务器后翻看 /var/log/auth.log,里面是成百上千条 Failed password for root 的记录。密码登录把服务器的安全性押在了两件很不牢靠的事情上:一是人能不能记住又长又随机的字符串,二是这台机器有没有暴露在公网上被人反复试错。SSH 密钥登录把这两件事都绕开了:私钥保存在你自己的终端设备上,从不经过网络,服务端只保存可以公开分享的公钥,认证依靠非对称签名而不是猜对字符串,爆破的成功率因此趋近于零。
密钥登录还顺带解决了另一个日常痛点:一次配置,处处免密。无论是登录云主机、拉取 Git 仓库,还是通过跳板机连接内网机器,都可以用同一套密钥和一份 ~/.ssh/config 描述清楚,不必再记一堆 IP、端口和口令。
二、在本地生成一对密钥
在本地终端执行下面这条命令即可生成一对 ed25519 密钥:
ssh-keygen -t ed25519 -C “office-macbook-2026” -f ~/.ssh/id_ed25519_cloud
三个参数分别表示:使用 ed25519 算法(密钥短、签名快、安全性优于同长度的 RSA)、给密钥加一段注释方便以后辨认、指定输出文件名。建议不要覆盖默认的 id_ed25519,按用途给密钥起名,例如 id_ed25519_cloud、id_ed25519_git,这样一台机器被回收时可以只撤销对应的那一把。
执行过程中会提示输入口令(passphrase)。这个口令保护的是本地私钥文件本身:即使笔记本丢失,别人拿到私钥文件也不知道口令,依然无法冒用。如果系统支持安全密钥(macOS 钥匙串、GNOME Keyring、Windows 凭据管理器),口令只需输入一次即可长期缓存。生成完成后 ~/.ssh 下会多出一对文件,id_ed25519_cloud 是私钥,绝对不要外发;id_ed25519_cloud.pub 是公钥,可以随意复制到任何你有权登录的服务器。
如果服务器系统较老、不支持 ed25519,可以改用 rsa 并指定足够长度:ssh-keygen -t rsa -b 4096 -C “office-laptop”。
三、把公钥交给服务器
最省事的方式是 ssh-copy-id:
ssh-copy-id -i ~/.ssh/id_ed25519_cloud.pub -p 22 root@203.0.113.10
它做的事情其实很简单:登录一次服务器,把你的公钥追加进对应用户的 ~/.ssh/authorized_keys。如果服务器只允许密钥登录、你手上只有别人帮忙放好的公钥,也可以手动完成,只要记住权限:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo “ssh-ed25519 AAAA… office-laptop” >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
.ssh 目录必须是 700,authorized_keys 必须是 600,属主必须是登录用户本人。权限稍宽(例如 755 或 644 且同组可写)时,sshd 会出于安全考虑直接忽略这份授权文件,继续报 Permission denied,这是新手最常踩的坑。
四、用 ~/.ssh/config 把连接习惯固化下来
IP、端口、用户名、密钥路径这些参数每次都在命令行里敲一遍,既累又容易出错。~/.ssh/config 可以把它们沉淀成一段段可读的配置:
Host cloud-test
HostName 203.0.113.10
Port 22022
User debian
IdentityFile ~/.ssh/id_ed25519_cloud
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
配置好之后,登录只需要 ssh cloud-test。几行配置带来的便利远不止短一点:IdentitiesOnly yes 告诉客户端只递交这一把密钥,避免 ssh-agent 里密钥太多而先递交了服务端不接受的那一把;ServerAliveInterval 让长时间空闲的连接不被中间设备悄悄切断。
多主机可以用通配符统一约定,再对个别主机做例外:
Host 10.0.*.*
User ops
IdentityFile ~/.ssh/id_ed25519_ops
StrictHostKeyChecking accept-new
跳板机(堡垒机)场景下,ProxyJump 一行就能把两跳变成一跳:
Host inner-db
HostName 10.0.8.21
User ops
ProxyJump cloud-test
于是 ssh inner-db 会先连到 cloud-test,再由它转发到内网地址,scp 与 rsync 同样适用。需要把远端端口映射回本地调试时,再加上 LocalForward 9000 127.0.0.1:9000 即可。
五、服务器侧的加固步骤
密钥可用之后,就该关掉密码这道门。编辑 /etc/ssh/sshd_config(Debian/Ubuntu 上建议把自定义项写进 sshd_config.d/ 下的独立文件),关注这么几项:
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
MaxAuthTries 3
LoginGraceTime 20
AllowUsers debian ops
PubkeyAuthentication 保持开启;PasswordAuthentication 与 KbdInteractiveAuthentication 一起关闭,否则改了前者仍然会被密码提示打回原形。PermitRootLogin prohibit-password 的含义是不允许 root 用密码登录,但仍允许用密钥。AllowUsers 显式列出允许登录的用户,能减少脚本类攻击面。
修改后务必用 systemctl reload sshd 让配置生效,并且不要关闭当前已经登录成功的会话,另开一个终端测试新会话能否用密钥登录成功后,再考虑进一步把端口改到高位、配合安全组只放行自己的 IP。最后再加一层 fail2ban 之类的防护,对仍然疯狂试探的地址做自动封禁,能显著降低日志噪声。
六、常见故障排查
登录失败时,先把 -v 加上:ssh -vT cloud-test,输出里会依次列出尝试过的密钥与服务端的反应,能直接看出是密钥没递交、权限不对还是算法被拒。几条高频结论:
第一,Unprotected private key file 或 Bad permissions,说明私钥文件权限过宽,执行 chmod 600 ~/.ssh/id_ed25519_cloud 即可。第二,WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED,通常是服务器重装或换 IP 导致主机指纹变化,用 ssh-keygen -R 对应的 HostName 清除旧记录后重新接受新指纹,这一步要确认确实是自己的服务器,不要习惯性忽略。第三,服务端日志里出现 Authentication refused: bad ownership or modes,回到第三节检查属主与权限。第四,新版客户端连接老服务器出现 no matching key exchange method,可在 config 里为该 Host 单独追加 KexAlgorithms 与 HostKeyAlgorithms 的兼容项,而不是全局放宽。
七、密钥的轮换、多设备与撤销
密钥不是配完就一劳永逸。建议为不同用途、不同环境使用不同密钥,并把公钥注释里的邮箱或设备名写得足够具体,例如 dev@macbook-office。同事离职或某台设备丢失时,只需从对应服务器的 authorized_keys 中删去那一行公钥,改动即时生效,无需重启 sshd。想定期轮换时,可以先追加新公钥、验证登录成功,再删除旧公钥,整个过程不影响在线会话。
如果你有多个终端设备,不必把私钥拷来拷去(拷贝私钥本身就是风险),正确做法是在每台设备上各自生成密钥、各自把公钥授权到服务器。云端 Git 仓库同理,把公钥粘贴到平台的 SSH Keys 设置页即可,无需把账号口令告诉任何人。
八、小结
本文从为什么出发,走完了 SSH 密钥登录的完整链路:用 ssh-keygen 生成 ed25519 密钥对,用 ssh-copy-id 或手动方式把公钥写入 authorized_keys 并保证 700/600 权限,用 ~/.ssh/config 里的 Host、IdentityFile、IdentitiesOnly、ProxyJump 等参数把连接习惯固化下来,最后在 sshd_config 中关闭密码登录、限制 root 与重试次数,完成服务器加固。整套配置做完,你会得到一台不再被密码爆破打扰、登录只需两个单词的服务器,也会有一份可以直接复用到下一台主机的标准流程。
- 点赞
- 收藏
- 关注作者
评论(0)