Skip to content

SSH 里的“认证私钥”到底是什么,它认证的是谁? ​

很多人在看到 SSH 配置中的“认证私钥”时,都会自然地理解成“用户登录时使用的私钥”。但这个理解通常是不对的。

SSH 里的两把私钥 ​

这里的关键在于,SSH 里可能同时出现两类私钥:

  • 服务器自己的私钥
  • 用户自己的私钥

它们都叫“私钥”,但用途并不一样。

如果配置界面中的“认证私钥”指的是 SSH 服务端配置项,那么它通常不是用户登录用的私钥,而是SSH 服务器身份私钥。它的作用不是证明“用户是谁”,而是证明“服务器是谁”。

也就是说,它认证的对象不是用户,而是服务器本身。

理解这一点后,很多常见疑问就会顺过来。比如:

  • 为什么已经开启了账号密码登录,系统里仍然需要这个私钥?
  • 为什么用户用公钥免密登录时,服务器也还是要有自己的私钥?
  • 为什么第一次连接 SSH 时,客户端会提示确认主机指纹?

这些问题,本质上都和“服务器身份认证”有关。

“认证私钥”属于哪一层认证 ​

SSH 建立连接时,并不是一上来就先验证用户密码。更常见的流程是,客户端先与服务器完成握手,并验证服务器身份;在此之后,双方建立加密通道;再之后,客户端才会提交用户名和密码,或者使用用户自己的 SSH 密钥完成登录认证。

所以在 SSH 里,至少有两件不同的事需要分开看:

  • 第一件事是确认“我连接的是不是目标服务器”
  • 第二件事是确认“这个用户能不能登录这台服务器”

前者依赖的是服务器身份私钥。 后者依赖的是用户密码或者用户私钥。

这也是为什么“认证私钥”和“账号密码”并不是二选一关系。它们分别解决的是不同层面的问题。

如果把整个过程再说得更明确一点,可以这样理解:

当客户端连接 SSH 服务器时,服务器会使用自己的身份私钥参与握手签名。客户端再根据服务器对应的公钥来验证这个签名是否正确。验证通过后,客户端才有理由相信,对面确实持有那把应属于目标服务器的私钥。

在这个阶段,服务器是在证明自己的身份。

只有这一步完成之后,客户端才会继续进行用户认证。例如提交用户名和密码,或者使用用户自己的 SSH 私钥来完成公钥认证。

因此:

  • 服务器身份私钥解决的是“服务器是谁”
  • 账号密码 / 用户 SSH 私钥解决的是“用户是谁”

两者名称相似,但职责完全不同。

这两层在服务端的生效配置里是分开呈现的。sshd -T 打印的是 sshd 实际加载的配置,而不是磁盘上那份带注释的文件,所以要看一台主机到底允许哪些用户认证方式,用它最快。下面是 Debian 12、OpenSSH 9.2p1 上的真实回显:

bash
$ sshd -T 2>/dev/null | grep -E 'pubkeyauthentication|passwordauthentication|kbdinteractive|authenticationmethods|authorizedkeysfile'
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2
authenticationmethods any

注意这份输出里没有任何一行是管服务器身份私钥的:用户认证方式可以随时开关,而主机密钥是通过单独的 hostkey 配置项指定的,并不存在“把它关掉”这种开关。

主机指纹与首次连接确认 ​

这也解释了一个很常见的误区:有些人会认为“既然我已经使用账号密码登录,那服务器端这个私钥就没用了”。实际上并不是这样。即使用户最终采用的是密码登录,服务器仍然需要先完成自己的身份证明。否则,客户端无法可靠确认自己连接的到底是不是预期中的服务器。

第一次连接某台 SSH 服务器时,客户端常常会提示确认主机指纹,原因也在这里。客户端虽然可以验证“对方持有某把私钥”,但在第一次连接时,它还不知道这把私钥是否属于你想连接的那台服务器。因此需要用户手动确认一次。确认之后,客户端会把该服务器的公钥信息记录下来,后续再连接时就可以据此判断主机身份是否发生变化。

你被要求确认的那个指纹,其实就是服务器上配置的主机公钥,可以在服务端用 ssh-keygen 直接还原出来:

bash
$ ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:634U97WwhXykruLOW0jgNCRjId8I6YWjpLJYlaic2Iw root@work (ED25519)
$ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub
3072 SHA256:pGBXexCOLhPzMcFEGXv7JuF5zB+SqIB4rUXeIuJbjfA root@work (RSA)

如果未来客户端提示主机指纹变化,通常意味着以下几种情况之一:

  • 服务器重装或重新生成了主机密钥
  • 当前连接的并不是原来的那台服务器
  • 存在中间人攻击风险

这也是为什么服务器身份私钥不能被随意替换,更不能泄露。

如果用户使用的不是密码登录,而是 SSH 公钥登录,情况也类似。区别只在于用户认证阶段不再提交密码,而是由用户使用自己的私钥对挑战数据进行签名,再由服务器用登记的公钥进行验证。

但无论用户使用哪种登录方式,前面的服务器身份认证步骤都仍然存在。换句话说:

  • 用户密码可以替换为用户私钥
  • 但服务器身份私钥不能因此消失

密码、公钥、证书与 OTP 的取舍 ​

如果放到产品配置界面里,更准确的说法其实不应该只是“认证私钥”,而应该写成:

SSH 服务器身份私钥

这样更不容易让用户误解为“登录私钥”或“用户认证私钥”。

在密码、公钥、证书、OTP 之间切换,改变的只是第二层“如何证明用户是谁”,都不会动到第一层。证书比单纯的 authorized_keys 又进一步:由 CA 给用户密钥签名,服务器只需要信任 CA,而不必逐台维护每一个公钥。证书本身还带着身份标识、有效期和 principals 列表,完全不用连到目标主机就能查看:

bash
$ ssh-keygen -t ed25519 -N '' -C 'alice@bastion' -f /tmp/ntdemo_1789174156/user_key -q
$ ssh-keygen -t ed25519 -N '' -C 'demo-ca' -f /tmp/ntdemo_1789174156/ca_key -q
$ ssh-keygen -s /tmp/ntdemo_1789174156/ca_key -I alice -n alice,webassets -V +12w /tmp/ntdemo_1789174156/user_key.pub
Signed user key /tmp/ntdemo_1789174156/user_key-cert.pub: id "alice" serial 0 for alice,webassets valid from 2026-09-12T08:48:00 to 2026-12-05T08:49:16
$ ssh-keygen -L -f /tmp/ntdemo_1789174156/user_key-cert.pub
/tmp/ntdemo_1789174156/user_key-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:XOpbC+9d91JQOcykc3tthQde8qG7KOA8I3qzZ5GhFOc
        Signing CA: ED25519 SHA256:dQzh8TvYLWvxDzZUeh1dQq8AJSMYtjKPkTRSmILmQAE (using ssh-ed25519)
        Key ID: "alice"
        Serial: 0
        Valid: from 2026-09-12T08:48:00 to 2026-12-05T08:49:16
        Principals: 
                alice
                webassets
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

这正是集中管控的意义:私钥始终不出用户机器,序列号和有效期由 CA 记录,吊销在 CA 侧完成,而不需要逐台主机处理。在开源堡垒机里,这种分离对应的就是凭证管理——资产登录凭据只存一份,由会话按需取用,可参见 凭证管理 与 SSH 服务器。

所以,这个问题最后可以归纳为一句话:

SSH 里的“认证私钥”如果是服务端配置项,通常认证的是服务器,不是用户。

用户是谁,由账号密码或用户自己的 SSH 私钥来证明。 服务器是谁,则由服务器自己的身份私钥来证明。

常见误区与排查 ​

下面三条检查基本能覆盖绝大部分困惑,而且各自回答的是不同的问题。

  • 这台主机实际允许哪些用户认证方式?用 sshd -T 过滤 passwordauthentication / pubkeyauthentication,看生效值,而不是 sshd_config 里被注释掉的那一行。
  • 服务器究竟呈现的是哪把密钥?用 ssh-keygen -l 读出主机公钥指纹,再和客户端首次连接时显示的指纹比对。不一致是事实,而不是一个可以随手点过去的提示。
  • 两端分别是什么实现?ssh -V 与 sshd -V 分别报客户端与服务端的版本,即使在一台补丁齐全的主机上,这两个字符串也常常不一样:
bash
$ ssh -V
OpenSSH_9.2p1 Debian-2+deb12u5, OpenSSL 3.0.15 3 Sep 2024
$ sshd -V
OpenSSH_9.2, OpenSSL 3.0.15 3 Sep 2024

在 Next Terminal 这类开源堡垒机中,SSH 资产的凭证管理与主机指纹校验正是为了解决这两类认证的分离问题,详见 资产管理 与 资产访问,亦可用 Termark 本地客户端 直连已授权的 SSH 资产。