1. 为什么要折腾免密登录:从一次抓狂的批量操作说起
如果你只在两三台机器上偶尔敲敲命令,密码登录确实够用。但一旦你开始管理五台、十台甚至更多Linux服务器,或者在写脚本批量同步配置、定时拉取日志、自动发布代码,你会发现每次都要输密码这件事会把人逼疯。
我自己第一次被逼到去研究免密登录,是因为一个深夜的故障处理。当时线上有六台应用服务器,需要逐个登录查看日志定位问题,每台机器都要输一遍root密码,输到第四台的时候我已经开始怀疑人生。更致命的是,当时有个临时脚本需要从跳板机向三台机器分发配置文件,脚本本身写好只要一分钟,但我守在旁边一遍遍输密码花了快十分钟——而且因为其中一台机器密码输错了一次,整个流程被迫重跑。
这就是SSH免密登录的核心价值:让机器之间的信任关系代替人肉输密码,从而实现批量操作的自动化和无人值守。它解决的不只是“省事”的问题,而是让一些原本不可能手动完成的操作成为可能——比如凌晨两点的定时备份、CI/CD流水线里自动部署到生产服务器、大规模集群的初始化配置。
这篇文章我会用两台CentOS主机作为示例(其他发行版如Ubuntu、Debian操作几乎一致),完整走一遍从生成密钥、分发公钥、验证登录到排查常见问题的全过程。同时会把每一步背后的原理讲清楚,让你不只是“照着敲能通”,而是真正理解这套信任机制是怎么工作的。
适合谁看:刚开始接触Linux运维的同学、需要配置自动化脚本的开发者、以及那些已经照着网上教程配过但没成功或者配完还是一头雾水的朋友。即使你之前完全没接触过SSH密钥,跟着这篇文章一步步操作也能搞定。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 免密登录背后的信任逻辑:公钥加密与授权文件
很多人照着教程执行成功了,但不知道自己到底做了什么,后面一遇到变体场景就懵。所以动手之前,我们先花五分钟把原理理清楚。
2.1 密码认证和密钥认证的本质区别
传统的密码登录,是客户端把密码传给服务端,服务端验证密码对不对,对了就放行。这个过程有两个隐患:一是密码在网络传输过程中有被截获的风险(虽然SSH协议本身会加密传输通道,但密码认证仍然面临暴力破解的威胁);二是密码认证要求每次连接都必须有人参与——要么人手动输入,要么把密码硬编码到脚本里(这是极度危险的做法,脚本泄露等于服务器裸奔)。
密钥认证则完全换了一套逻辑。它基于非对称加密,核心是一对密钥:
- 私钥(private key):留在客户端,权限必须严格控制,相当于你的身份证原件。
- 公钥(public key):分发到所有你想免密登录的服务器上,相当于你提前在门卫处备案的“通行证样本”。
登录过程大致是这样:
- 客户端发起SSH连接,告诉服务端“我是某某用户,我带了密钥”。
- 服务端在自己的授权列表(authorized_keys文件)里查找是否有对应的公钥记录。
- 找到后,服务端生成一段随机数据,用你的公钥加密,发给客户端。
- 客户端用自己的私钥解密这段数据,再把结果回传给服务端。
- 服务端验证解密结果正确,确认“你确实持有与公钥配对的私钥”,放行登录。
整个过程私钥始终不出客户端本机,网络上传输的只是加密后的验证数据,即使被截获,没有私钥也无法伪造身份。这就是为什么密钥认证比密码认证更安全、更适合自动化场景。
2.2 授权文件 authorized_keys 和 known_hosts 的角色
这里有两个特别容易混淆的文件,一个是服务端的authorized_keys,一个是客户端的known_hosts,弄不清它们会导致很多奇怪的报错。
authorized_keys:存放在服务端用户家目录下的.ssh文件夹里,路径通常是~/.ssh/authorized_keys。这个文件里每行存放一个公钥,代表“允许哪个公钥对应的私钥登录当前用户”。比如你在主机B上把A机的公钥追加进了root用户的authorized_keys,那A机就可以免密登录B机的root用户。
known_hosts:存放在客户端用户家目录下,路径是~/.ssh/known_hosts。它记录的是你曾经连接过哪些服务器,以及那些服务器的主机指纹(host key)。它的作用是防止中间人攻击——如果有人冒充服务器,指纹对不上,SSH客户端就会警告你。当你第一次SSH连接一台新服务器时,终端会问你是否信任这个主机指纹,就是这个文件在起作用。
注意这个区别非常重要:authorized_keys决定“谁能进”,known_hosts决定“我认不认识这台机器”。前者是授权机制,后者是防伪机制。
2.3 权限为什么那么敏感
Linux下SSH对文件权限极其敏感,这是大多数免密配置失败的头号原因。核心权限要求如下:
| 路径或文件 | 要求权限 |
|---|---|
| 用户家目录(~) | 755或更严格(不能是777) |
| .ssh目录 | 700 |
| authorized_keys文件 | 600 |
| 私钥 | 600 |
| 公钥 | 644 |
这些权限要求不是SSH开发者闲得慌,而是实打实的安全底线。如果.ssh目录权限过宽(比如777),意味着系统上的其他用户也能进去篡改你的authorized_keys文件,往里面塞一个他们自己的公钥,那你的服务器等于对人家敞开大门。所以SSH在验证时会严格检查权限,一旦发现权限过宽,直接拒绝使用这个密钥,防止被攻击者利用。
我在实操中发现一个规律:权限问题导致的失败,报错信息往往很有迷惑性,不会直接说“权限不对”,而是说“Permission denied (publickey)”,排查起来很费劲。所以配置时最好一次性把权限设对,后面出的很多问题都能从源头避免。
3. 动手前的心跳检查:确认SSH服务、网络与基础环境
很多人配置免密失败,卡在的不是后面的密钥操作,而是最基础的环境检查没做。你想,如果A机连B机的SSH端口都连不通,后面生成再多密钥也是白搭。
3.1 确认两台机器的SSH服务状态
首先在目标机器(B机,即被登录方)上确认SSH服务是否正常运行:
bash复制systemctl status sshd
看到active (running)就说明服务正常。如果没在运行,启动并设置开机自启:
bash复制systemctl start sshd
systemctl enable sshd
有些系统用的是service ssh status,或者服务名不叫sshd而叫ssh(Debian系),按自己系统的实际服务名来即可。
另外要确认SSH服务的端口号。默认是22,但很多生产环境为了安全会改成其他端口,比如22022。这一步直接影响后面的命令参数——源机器(A机)连接时如果没指定端口,会默认连22,那就连不上了。
查看sshd配置文件确认端口:
bash复制grep -i "^Port" /etc/ssh/sshd_config
如果这里显示的端口不是22,后面所有ssh命令都要带上-p 端口号参数。
3.2 测试网络连通性
在源机器(A机)上测试到B机的网络连通性:
bash复制ping -c 4 192.168.1.100
ping通只代表网络通,不代表SSH端口通。进一步检查SSH端口:
bash复制telnet 192.168.1.100 22
或者用更轻量的方式:
bash复制ssh -p 22 user@192.168.1.100
如果出现密码输入提示,说明端口通、SSH服务也在正常工作,这一步的风险面已经排除了。如果telnet显示连接被拒绝或超时,优先检查:
- 防火墙是否放行了SSH端口(firewalld或ufw或iptables)
- 云服务器的安全组是否放行了对应端口
- 能否ping通(排除基础网络故障)
防火墙这一层太多了,我单独拎出来说。
3.3 防火墙与SELinux的坑
这里重点说防火墙,因为踩的人实在太多了。
如果是CentOS/RHEL系且启用了firewalld:
bash复制systemctl status firewalld
如果是开启状态,确认22端口(或你改过的自定义端口)在规则里:
bash复制firewall-cmd --list-all
如果端口没有放行,执行:
bash复制firewall-cmd --permanent --add-port=22/tcp
firewall-cmd --reload
更稳妥的做法是只允许特定来源IP访问SSH端口,而不是对所有IP开放。但这个属于安全加固范畴,不是本文重点,初学者先把连通性搞定再说。
Ubuntu/Debian系检查ufw:
bash复制ufw status
如果显示active,放行22端口:
bash复制ufw allow 22/tcp
还有一个容易忽略的是SELinux。CentOS默认开启SELinux,它可能限制sshd读取你新建的authorized_keys文件。如果你发现公钥都拷贝过去了、权限也全部正确,但就是登录失败,可以用getenforce看看SELinux状态。临时关闭验证:
bash复制setenforce 0
如果关了SELinux后登录成功,说明问题出在SELinux的sshd策略上。此时不要图省事直接永久关闭SELinux,而是用正确的办法——恢复SELinux上下文:
bash复制restorecon -Rv ~/.ssh
这个命令会把.ssh目录下的文件恢复为正确的SELinux标签。我实测遇到过,公钥文件和权限都对,但restorecon之后就通了,非常值钱的一个坑。
注意:SELinux是个大话题,这里只提到与SSH免密相关的部分。生产环境建议保持SELinux开启,用
restorecon或自定义策略来解决问题,而不是简单粗暴地关闭。
4. 核心操作全流程:生成密钥对、分发公钥、验证登录
环境就绪后,正式开始配置。整个流程分三步:在源机器上生成密钥对、把公钥放到目标机器的授权文件里、测试免密登录。
4.1 在源机器上生成密钥对
登录A机,执行:
bash复制ssh-keygen -t rsa -b 4096
这条命令的含义:
-t rsa:指定密钥类型为RSA。现在Ed25519算法也被广泛支持,更短更快更安全,可以用ssh-keygen -t ed25519替代。-b 4096:指定密钥长度4096位。RSA密钥越长越安全,但生成和验证的耗时会略有增加,对日常管理来说4096位是推荐值。用Ed25519的话不需要-b参数,密钥长度固定。
执行后会提示你选择密钥保存路径,默认是~/.ssh/id_rsa(或id_ed25519),直接回车用默认值。接下来会要求设置私钥的密码(passphrase),这里有两个选择:
- 直接回车不设密码:私钥裸奔在磁盘上,任何能访问这台机器的人都可以直接使用这个私钥免密登录。好处是自动化脚本不用额外输入,坏处是安全性下降。
- 设置一个密码:每次使用私钥时要输入这个密码(可以通过ssh-agent缓存,后面细说)。好处是即使私钥泄露,没有密码也无法使用。坏处是纯自动化场景会多一道坎。
我的建议是:纯个人管理、机器物理安全可控的,可以不设passphrase;但如果是共享机器、有被入侵风险的,务必设置。怎么权衡,取决于你的安全需求。
生成好之后,在~/.ssh/目录下会有两个文件:
id_rsa(私钥,权限600,绝对不能外传)id_rsa.pub(公钥,可以随意分发)
查看公钥内容:
bash复制cat ~/.ssh/id_rsa.pub
公钥是一长串以ssh-rsa AAAA...开头的文本,后面通常跟着user@hostname的注释。
4.2 把公钥传给目标机器的三种方式
公钥要放到B机的~/.ssh/authorized_keys文件里,有三种方式可以实现。
方式一:ssh-copy-id(最推荐)
在A机执行:
bash复制ssh-copy-id root@192.168.1.100
这个命令会自动处理很多事情:读取A机默认的公钥、SSH登录B机(此时需要输入B机root用户的密码)、在B机的.ssh目录下创建authorized_keys文件(不存在的话)、把公钥追加进去、设置正确的权限。
这里注意一个细节:ssh-copy-id会把你家目录下所有.pub结尾的公钥都拷过去。如果你生成了多个密钥,但又不想全部授权到这台机器上,需要指定具体的公钥文件:
bash复制ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.100
方式二:手动追加
如果ssh-copy-id命令在你的系统上不存在(比如某些精简版系统),可以手动操作。在A机查看公钥内容:
bash复制cat ~/.ssh/id_rsa.pub
然后复制输出内容,在B机上执行:
bash复制mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "粘贴公钥内容" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
注意:>>是追加,不会覆盖已有的其他公钥。如果B机原先已有authorized_keys文件,且文件中已经有一些公钥,用>会直接清空文件,导致其他机器的免密全部失效,这是一个非常常见的翻车现场,务必用追加。
方式三:通过scp一次性搞定
A机执行:
bash复制scp ~/.ssh/id_rsa.pub root@192.168.1.100:/tmp/
然后在B机执行:
bash复制mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
rm -f /tmp/id_rsa.pub
这个方法适合网络环境特殊、ssh-copy-id用不了,或者你习惯拆开一步步操作的情况。
4.3 权限设置:最容易忽略的细节
在上面操作完成后,无论用的是哪种方式,最后一定要检查B机上的权限是否正确:
bash复制ls -ld ~
ls -ld ~/.ssh
ls -l ~/.ssh/authorized_keys
合法的权限组合是:
- 家目录:755或者700(不能是777)
.ssh目录:700authorized_keys文件:600
如果发现权限不对,直接修正:
bash复制chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 755 ~
提示:很多教程不会强调家目录权限,但一些配置了严格sshd策略的系统(比如CentOS默认的
StrictModes yes)会检查家目录权限。如果家目录是777或者组/其他用户有写权限,SSH会拒绝读取公钥文件。
4.4 验证免密登录
一切配置完成后,在A机执行:
bash复制ssh root@192.168.1.100
如果直接进入了B机的shell,没有提示输入密码,恭喜你,配置成功。
如果提示输入密码,说明公钥认证没有被接受,你看到的其实是密码认证的退路。这时不要急着输入密码,按Ctrl+C退出,开始排查(下一章会详细讲)。
验证通过后可以进一步查看调试信息,确认确实是公钥认证生效:
bash复制ssh -v root@192.168.1.100
-v参数(verbose)会打印SSH连接细节,在输出中找到类似Authenticated with partial success或Authenticated to ... using "publickey"的字段,就确认使用公钥认证成功。
4.5 一个易踩的细节:root用户和普通用户的差别
上面示例用的是root用户。如果你有两个普通用户(比如A机的user1、B机的user2),流程完全一样,只是文件路径变成对应用户的家目录,连接时指定对应用户名:
bash复制ssh-copy-id user2@192.168.1.100
ssh user2@192.168.1.100
需要注意的是,如果B机的sshd配置了PermitRootLogin no,那root用户的免密也会被拒绝。这时要么用普通用户操作,要么修改sshd配置。生产环境一般不建议允许root直接登录,所以如果条件允许,用普通用户 + sudo更符合安全实践。
5. 排查"配了还是免密不了":常见问题的整套定位思路
这是整个免密配置里最让人头秃的环节。一次配置成功很幸福,但配置失败后的排查往往才是真正考验人的地方。我在这一节把常见失败场景串成一条完整的排查链路,你可以按顺序一步步验证。
5.1 第一道排查:确认服务端开了公钥认证
在B机的sshd配置文件中确认(路径通常为/etc/ssh/sshd_config):
bash复制grep -E "PubkeyAuthentication|PasswordAuthentication" /etc/ssh/sshd_config
PubkeyAuthentication应该为yes,PasswordAuthentication可按需设置。如果PubkeyAuthentication no被显式配置,公钥认证直接被禁用,免密当然不可能成功。修改配置后重启sshd:
bash复制systemctl restart sshd
有一种情况容易被忽视:有的云镜像默认不允许root通过密码登录,但是在/etc/ssh/sshd_config的Match块里单独做了覆盖配置。只查看全局配置是不够的,建议grep -v "^#"看一下所有生效行。
5.2 第二道排查:客户端是否用了正确的私钥
A机默认会读取~/.ssh/id_rsa或~/.ssh/id_ed25519。如果你生成密钥时把文件名改成了自定义名称(比如mykey),ssh默认找不到。
用-i参数显式指定:
bash复制ssh -i ~/.ssh/mykey root@192.168.1.100
另一种情况:你有多对密钥,但默认那把不是B机授权的。可以用-v看debug输出里Offering public key用的哪个文件。
5.3 第三道排查:authorized_keys文件内容是否正确
在B机检查:
bash复制cat ~/.ssh/authorized_keys
确认B机上的公钥内容和A机的id_rsa.pub完全一致。这里有个不易察觉的坑:复制公钥时,如果用了不合适的编辑器或终端,可能会把长行折行,或者把结尾的换行符弄丢。authorized_keys文件每一行必须恰好是一条完整的公钥,不能有额外的空格或折行。
另外注意,A机的公钥文件注释部分(user@hostname)不影响认证,但如果你手动编辑过公钥内容,一个字符都不能错。
如何精确对比?在A机生成公钥的哈希,在B机同内容里做对比:
bash复制# A机上执行
ssh-keygen -lf ~/.ssh/id_rsa.pub
# B机上执行
ssh-keygen -lf ~/.ssh/authorized_keys
两条命令输出的指纹摘要应该一致。这是我最常用的快速比对手段,不用慢慢数ssh-rsa那串长字符。
5.4 第四道排查:权限与SELinux(重灾区)
在B机上看权限:
bash复制ls -ld ~ ~/.ssh
ls -l ~/.ssh/authorized_keys
权限不对就改,具体见4.3节。如果权限都对依然失败,且系统开启了SELinux,执行:
bash复制restorecon -Rv ~/.ssh
这个命令实际项目中帮我解决了不止一次问题,特别是从别的目录拷贝或移动过公钥文件时,文件的SELinux上下文会停留在原路径类型,sshd读取时被SELinux拦下。
5.5 第五道排查:从sshd日志中定位
如果你把前面的都验证了一遍还是不行,是时候看日志了。在B机上查看sshd日志:
bash复制journalctl -u sshd -n 50
或者:
bash复制tail -50 /var/log/secure
日志里通常会有明确的原因提示。常见的几条及对应含义:
| 日志内容 | 含义 |
|---|---|
Authentication refused: bad ownership or modes |
文件权限问题,检查家目录、.ssh、authorized_keys权限 |
Permission denied (publickey,password) |
公钥验证失败,继续检查公钥内容或sshd配置 |
no more authentication methods to try |
所有认证方式都失败,客户端可能没提供有效私钥 |
Offering public key: ... 后跟Authentications that can continue |
客户端发了公钥但服务端认为无效 |
Connection closed by authenticating user |
可能是SELinux拦截,或者权限过宽 |
看日志是最直接的定位方式。遇到问题建议先看日志,别盲猜。
5.6 一个极易被误解的坑:known_hosts的主机指纹不匹配
有时候报错长这样:
code复制@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
这跟免密的密钥认证没有直接关系,是known_hosts里的主机指纹和B机实际提供的不一致。常见原因是B机重装过系统或sshd重新生成过host key。
此时确认B机没有异常,可以先移除旧的指纹记录再重连:
bash复制ssh-keygen -R 192.168.1.100
然后重新连接,会提示是否信任新的主机指纹,输入yes即可。这是一个很容易被误解为“免密配置失败”的报错。
6. 进阶玩法:批量分发密钥与自动化运维的衔接
免密登录配好之后,最大的价值在于它解锁了很多自动化操作。这一节聊几个实际使用中非常高频的进阶场景。
6.1 用ssh-agent管理加密私钥
如果你给私钥设置了passphrase(就是生成密钥时设置的那个密码),每次SSH登录时都会要求输入。自动化场景下显然不希望这样。解决方案是ssh-agent:
bash复制eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa
执行后会要求输入一次passphrase,之后该会话期间再使用这个私钥免密登录时,不再提示输入。ssh-agent的作用相当于在你的会话内存中暂存了解锁后的私钥。
注意:ssh-agent是会话级的,重启终端或重新登录后需要重新添加。可以把ssh-add命令加到~/.bashrc里,登录时自动添加,但要注意安全性。
另外,如果私钥没有设置passphrase,就不需要ssh-agent这一套,直接就能用。
6.2 规模化场景:向多台机器批量分发公钥
手动一台一台ssh-copy-id在机器少的时候没问题,但二三十台机还手动一个个来,配置效率就太低了。提供一个简单的批量脚本思路,用expect来自动应答密码:
bash复制#!/usr/bin/expect
set timeout 10
set host [lindex $argv 0]
set password "your_password"
spawn ssh-copy-id -i ~/.ssh/id_rsa.pub root@$host
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "$password\r" }
}
expect eof
然后循环调用:
bash复制for ip in 192.168.1.11 192.168.1.12 192.168.1.13; do
./copy_key.exp $ip
done
密码硬编码在脚本里,用完后及时删除脚本,注意安全。更安全的做法是用Ansible等配置管理工具,它支持authorized_key模块一键分发,但那是另一个更大的话题了。
6.3 免密登录后的常见自动化场景
配置好免密后,你的脚本和CI/CD流水线就可以直接用SSH进行远程操作:
- 批量命令执行:
for ip in $(cat ip_list); do ssh root@$ip "uptime && df -h"; done,一次查看所有机器的负载和磁盘使用。 - 定时远程备份:在crontab里添加任务,定时把远程机器的数据库备份拉到本地。
- 自动部署:CI/CD流水线里,构建完成后通过
scp推送到生产服务器并执行重启命令。 - 日志集中采集:用
ssh+tail或rsync把多台机器的日志拉到日志服务器。
注意一个细节:在脚本中写死SSH连接时,建议带上-o StrictHostKeyChecking=no或提前在known_hosts中记录主机指纹,否则第一次连接新主机时的交互式确认会卡住脚本。但生产环境使用StrictHostKeyChecking=no有安全风险,更稳妥的是提前把目标主机指纹写入known_hosts。
6.4 多用户共管服务器时,免密的组织方式
在一个团队共管一批服务器时,每个成员在自己的电脑上生成自己的密钥对,把各自的公钥加到对应服务器的authorized_keys里。这样每个人的登录身份是独立的,配合sudo权限控制,可以做到比较清晰的审计链路。
小团队可以考虑在一台管理机上为每个线上主机建一个别名(在~/.ssh/config里配置):
code复制Host web-server-1
HostName 192.168.1.11
User root
Port 22
IdentityFile ~/.ssh/id_rsa
Host db-server
HostName 192.168.1.20
User root
Port 22
IdentityFile ~/.ssh/id_rsa
配置之后直接ssh web-server-1就能连上,不用再记IP和用户名。
7. 安全加固:配好免密之后的必修课
配置完免密不代表整件事就结束了,安全层面还有几件事需要做。
7.1 私钥的保管原则
私钥等同于一串能直接打开你服务器的钥匙,泄露等于服务器裸奔。几个原则:
- 不要随意拷贝私钥到不信任的机器。
- 不要提交私钥到Git仓库,这一条血的教训太多。
- 私钥文件权限必须是600,并定期检查。
- 如果怀疑私钥泄露,第一时间在服务端把对应公钥从authorized_keys里删除,然后重新生成密钥。
7.2 服务端安全选项建议
在/etc/ssh/sshd_config中,有几个和免密相关的安全配置:
bash复制PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
PasswordAuthentication no意味着禁止密码认证,只允许密钥认证。这能有效防止暴力破解——攻击者连猜密码的入口都没有了。这个选项适合纯密钥管理的场景,但要确保所有需要登录的人都已经配置好密钥,否则会把所有人锁在门外。实操上有个稳妥做法:先在全部人员密钥配置完成、测试用密钥都能登录后,再关闭密码认证。
PermitRootLogin prohibit-password允许root用密钥登录,但禁止root用密码登录,是介于“完全禁止root登录”和“允许root密码登录”之间的折中方案。
7.3 定期轮换密钥
密钥不是配置一次就永久安全。建议定期重新生成密钥对,更新所有服务器上的authorized_keys。轮换时注意:先在全部需要登录的客户端生成新密钥,把公钥分发到各服务器,确认新密钥登录正常后,再删除旧的公钥记录。中途不要急着删旧密钥,否则你会发现自己被关在门外。
8. 我的实操体会:几个值钱的经验教训
最后聊几点上面没有细说的、纯粹来自实际操作的经验。
第一,配置免密前先在客户端用-v看一次完整输出。ssh -v user@host的输出信息量很大,虽然一开始看会有点懵,但里面的Offering public key、Authenticated、Permission denied这些关键行,能帮你快速定位问题出在哪一端。不看日志盲目重试是效率最低的排查方式。
第二,不要在修改sshd_config后不重启服务端就测试。我见过很多次配置改了没重启,然后一脸茫然地说“明明配置了为什么没生效”。改完配置后systemctl restart sshd,然后另开一个终端测试,别把当前连接断开——万一配置写错,当前连接可能是你唯一能进去修复的机会。
第三,给机器设置一个“后门”。我管理服务器时,永远保证至少有一条应急登录路径:要么是带外管理卡、要么是云控制台的VNC、要么是至少一台机器支持密码认证。免密配置玩得再熟,也有可能在某个时间点把自己锁在门外。设置好后门不是杞人忧天,是运维的基本生存哲学。
第四,公钥分发要及时更新。有时候团队成员离职、机器退役,旧的公钥还残留在服务器的authorized_keys里。时间久了文件里堆满了历史遗留的密钥,真出了安全问题排查起来头大。建议定期review服务器上的authorized_keys文件,删除不再需要的公钥条目。
第五,考虑用注解管理公钥来路。在authorized_keys里追加公钥时,可以在该行前面(或者用公钥自带的user@hostname注释)标注好这个公钥是谁的、哪台机器用的。因为公钥本身无法直观看出属于谁,不标注的话等三个月后回来看,里面几十行公钥,谁是谁已经完全对不上号了。
到这里,两台Linux主机间的SSH免密登录算是完整走了一遍,包括底层原理、实际操作步骤、问题排查、进阶自动化和安全加固。自动化这件事,表面上是省了一次输密码的时间,实质上是在为更大规模的管理效率打基础。按这篇文章的思路一步步来,搭配自动化的后续操作,你的Linux服务器管理会轻松很大一截。
