1. 项目源头:为什么不认识的IP会被SSH拦住
做运维和开发这些年,SSH连接遇到最多的一个问题就是“新IP的 SSH 指纹添加到 known_hosts 文件”。尤其是刚接手一批新服务器、或者公司内部网络换了一波IP的时候,终端里永远是一屏警告。第一次连接一台新主机,SSH客户端会提示:
code复制The authenticity of host '192.168.1.20 (192.168.1.20)' can't be established.
ED25519 key fingerprint is SHA256:jKx+VnZgtQ7xxuOP+G1b9K0vM9K/xxx.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
很多人直接敲一个yes就过去了,后面也就正常用。但如果你面对的不是一台,而是三十台、五十台新IP,每一台都要手动确认一遍,这活儿就变得极其机械。更麻烦的是,虚拟机、容器、云主机这类场景经常是脚本批量创建的,今天IP是这个,明天重建就换了,于是known_hosts里残留的旧指纹和新的指纹打架,终端直接给你一句“Host key verification failed”。
这个警告背后其实是一整套信任机制。SSH在建立连接时,除了验证用户名密码或者密钥,还要验证“对方确实是那台机器”。新IP意味着本地还没有它的指纹记录,所以SSH需要你来做一次信任确认。这篇文章我会把从“不认识”到“写入known_hosts”的整个流程拆开讲:known_hosts文件里到底存了什么、第一次连接时发生了什么、为什么有时换个IP也会被卡住、有哪些办法能把指纹提前写进文件、批量场景下怎么处理最省事,以及指纹校验的安全边界在哪里。不管你是刚入门的小白,还是已经在生产环境里摸爬滚打过几年的运维,这套内容应该都能直接用上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 指纹机制拆解:known_hosts 文件里到底存了什么
2.1 主机密钥是服务器的“身份证”
每个SSH服务端在安装或者首次启动时,都会生成一组主机密钥,默认存放在 /etc/ssh/ 下面。不同版本、不同发行版的密钥文件命名略有差别,常见的包括:
- ssh_host_rsa_key / ssh_host_rsa_key.pub
- ssh_host_ecdsa_key / ssh_host_ecdsa_key.pub
- ssh_host_ed25519_key / ssh_host_ed25519_key.pub
这些密钥是这台机器的“身份证”。客户端连接时,服务端会把自己的主机公钥发给客户端。公钥是一长串base64编码的字符串,直接展示根本没法用人眼比对,所以SSH协议会把公钥再做一次哈希,生成一个短指纹,默认是SHA256格式,形如:
code复制SHA256:9nWnQDVhKakB5dN7eLvWxwFD8uBkCVWGl2XmY6VZPQQ
客户端拿到这个指纹后,和known_hosts文件里记录的内容做比对,一致就继续,不一致就终止并报警。这个机制和HTTPS的证书校验有相似之处,都是要解决“我连的到底是不是我想连的那台机器”的问题。
有个点要特别说明:主机密钥和管理员密码是两回事。你改密码、加用户、重启服务,都不会影响主机密钥;但如果你重装系统、用虚拟机模板复制机器、或者重建容器,主机密钥基本都会变,这就直接导致后面要说的指纹不匹配问题。所以,一台机器只要身份变了,再有权限的运维也没法让老客户端的known_hosts自动“原谅它”,必须主动更新指纹记录。
2.2 known_hosts 文件的行格式和路径
known_hosts的默认位置是当前用户的 ~/.ssh/known_hosts,系统级位置是 /etc/ssh/ssh_known_hosts。每个用户维护一份自己的known_hosts,root维护一份root的,普通用户维护一份普通用户的,彼此不互通。具体每一行记录大致长这样:
bash复制192.168.1.20 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGq3fN...
如果你开启了HashKnownHosts(很多发行版默认开启),这一行的开头会变成一个哈希串,形如:
bash复制|1|abc123...=|xyz456...= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGq3fN...
这段哈希就是主机名/IP经过SHA1加盐处理之后的结果,好处是known_hosts文件不会直接暴露你常连的服务器地址,坏处是没法通过文本搜索反查某条记录对应哪台机器。
一行记录一共三个字段:主机名标记、密钥类型、base64编码的公钥内容。密钥类型常见的包括 ssh-rsa、ecdsa-sha2-nistp256、ssh-ed25519。在known_hosts中,同一个IP可以有多行,分别对应不同类型的密钥,因为服务端可能同时支持多种算法,客户端会根据协商结果选择其中一种来校验。所以用ssh-keyscan扫一台机器,默认会输出好几行,每行密钥类型不一样,这很正常。
还需要注意一个细节:如果连接
