SSD Nodes Learn
指南 Matt Connor作者: Matt Connor · 更新于 2026-07-19

SSH 密钥管理基础

了解 SSH 密钥的原理与管理方法:每台设备一把 ed25519 密钥、sshd 要求的文件权限、config 里的 Host 块,以及如何吊销丢失的密钥。

SSH 密钥是如何工作的

SSH 密钥是一对文件:私钥留在您的设备上,公钥则复制到每一台您想登录的服务器上。连接时,服务器用公钥发出一道只有对应私钥才能回答的问题。私钥从不离开您的设备,因此没有任何秘密会经过网络传输,一台被攻陷的服务器上也没有任何可偷的有用之物。这正是密钥优于密码的原因。把 SSH 密钥管理好,归结为四个习惯:每台设备一把密钥、sshd 要求的文件权限、一个让您不必再敲各种选项的 ~/.ssh/config 文件,以及在笔记本丢失当天知道如何移除一把密钥。

本文在 Ubuntu 24.04 上逐一讲解这些习惯,不过这里几乎所有内容都适用于任何 Linux 服务器和任何较新的 OpenSSH。

开始之前先说清一个术语,因为它能避免真实的错误。公钥不是秘密。您可以把它粘进工单、用邮件发送、甚至公开发布,没有人能凭它登录。私钥才是秘密。任何人只要复制了这个文件,并知道它的口令(如果设了口令的话),在您的服务器眼里就等同于您本人。

创建密钥:ed25519 是正确的默认选择

在您自己的电脑上,而不是在服务器上,运行:

ssh-keygen -t ed25519 -C "laptop"

-t ed25519 选择密钥类型。Ed25519 是现代的默认选择:密钥短小、速度快,自 2014 年以来的每个 OpenSSH 版本都支持它。只有当您必须与一台不认识 ed25519 的老旧设备通信时,才退回到 ssh-keygen -t rsa -b 4096-C "laptop" 设置一段注释。这段注释在密码学上不起任何作用,但两年后当您在服务器的 authorized_keys 文件里看到它时,就是靠它认出这把密钥的,所以请以密钥所在设备来命名。

ssh-keygen 会询问把密钥保存到哪里。接受默认值 ~/.ssh/id_ed25519。接着它会询问口令。请设一个;下面的口令小节会解释它为何在日常中几乎不花您任何代价。最后您会得到两个文件:~/.ssh/id_ed25519 是私钥,~/.ssh/id_ed25519.pub 是公钥。看一看公钥这一半:

cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3k2s0vQx7GdKQhX1yBz... laptop

它只有一行:密钥类型、密钥材料,以及您的注释。这一行就是最终要放到您服务器上的内容。

每台设备一把密钥,而不是每台服务器一把

每个人最先问的问题:我需要为每台服务器都新建一把密钥吗?不需要。为您敲键盘的每台设备创建一把密钥,把那一把公钥放到该设备需要访问的每一台服务器上。密钥标识的是设备。每台服务器上的 authorized_keys 文件,就是允许进入的设备清单。

这才是能扩展的模型,而其他做法都会以可预见的方式失败。每台服务器一把密钥,意味着一台连着二十台服务器的笔记本要带着二十把私钥,您很快就分不清哪把是哪把。所有设备共用一把密钥则更糟:笔记本被偷时,您没法只吊销这台笔记本而不同时把台式机也锁在门外,因为它们持有同一把私钥,于是您只能到处替换密钥,并一次性把新密钥重新分发到每一台设备。

采用每台设备一把密钥后,丢失的笔记本每台服务器只花您一行代价:从 authorized_keys 里删掉那台笔记本对应的那一行,其他每台设备都照常工作。您用 -C 设的注释,正是让这一行容易被找到的东西。

这个模型背后的规则是:私钥在一台设备上创建,也随这台设备一起消亡。绝不要把私钥复制到第二台机器,也绝不要把它上传到服务器。当一台新设备需要访问权限时,就在它上面生成一把新密钥。

把公钥放到服务器上

最省事的方式是 ssh-copy-id,它随 OpenSSH 一起提供:

ssh-copy-id matt@10.0.0.10

它会用当前还能用的方式(通常是密码)登录,把您的公钥追加到服务器上的 ~/.ssh/authorized_keys,如果目录和文件不存在,还会用正确的权限创建它们。测试方法是开一个新的 SSH 会话:服务器应当不再询问账户密码就让您进入。如果您的密钥设了口令,可能是您自己的机器改为询问口令;那个提示是本地的,并不是服务器密码。

当密码登录已经被禁用时,ssh-copy-id 就进不去了,于是您需要手动添加这一行。通过一个仍然可用的会话,或者您服务商的网页控制台登录,然后在服务器上运行:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3k2s0vQx7GdKQhX1yBz... laptop" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

把您真正的公钥粘进引号内,也就是 id_ed25519.pub 里那完整的一行。authorized_keys 每行一把公钥,它就是全部的访问数据库:添加一台设备就是追加一行,吊销一台设备就是删掉一行。在一台全新的服务器上,这一步属于新 VPS 的前 10 分钟,就在您关闭密码登录之前。

会让密钥登录失败的权限

这是密钥登录失败最常见的方式,而且它在客户端一侧悄无声息地失败。在 Ubuntu 24.04 上 sshd 默认以 StrictModes yes 运行,这意味着它拒绝使用一个其他用户也能编辑的 authorized_keys 文件。如果这个文件、~/.ssh 目录、或者您的主目录能被您以外的任何人写入,sshd 就会忽略您的密钥并退回去询问密码,而客户端得不到任何解释。(Ubuntu 的 OpenSSH 只容忍一种狭窄情形:文件对您自己的私有用户组可写,而这个组里没有别人。不要依赖它;请保持下面的权限模式。)真正的原因只出现在服务器的日志里:

sudo grep 'Authentication refused' /var/log/auth.log

在一个没有 rsyslog 的最小镜像上没有 auth.log;同样的这行出现在 journal 里:sudo journalctl -u ssh | grep 'Authentication refused'

Authentication refused: bad ownership or modes for file /home/matt/.ssh/authorized_keys

修复方法是两处权限更改加上一次归属检查,在服务器上以受影响的那个用户运行:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R matt:matt ~/.ssh

要记住的规则是:.ssh 目录设 700,里面的一切设 600。同样的数字也适用于您自己的电脑,因为客户端也会检查。一把能被其他用户读取的私钥,会让 ssh 直接拒绝这把密钥,而这一次错误提示很响亮:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/matt/.ssh/id_ed25519' are too open.

chmod 600 ~/.ssh/id_ed25519 就能修好它。

~/.ssh/config:不用再敲各种选项

在您自己电脑上的一个 ~/.ssh/config 文件,能给每台服务器起一个短名字,并记住您反复敲的那些选项。用 600 权限创建它,为每台服务器加一个 Host 块:

Host web1
    HostName 10.0.0.10
    User matt
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host db1
    HostName 10.0.0.11
    User matt
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

现在 ssh web1 就替代了 ssh -p 22 matt@10.0.0.10,同一个短名字在 scprsyncgit 里也都能用,因为它们都读取这个文件。HostName 是真实地址,User 省去您敲账户名,IdentityFile 则钉定要提供哪把密钥。

IdentitiesOnly yes 值得单说一句,因为它修复了一种令人困惑的失败。当您的 agent 持有好几把密钥时,客户端会一把接一把地提供它们,而服务器把每一次提供都算作一次失败尝试。加载的密钥一多,您就会在正确的那把还没被尝试之前收到 Received disconnect: Too many authentication failuresIdentitiesOnly yes 让客户端只提供 IdentityFile 里指定的那把密钥,于是这种失败根本不会发生。

口令与 ssh-agent

口令会把磁盘上的私钥文件加密。没有口令,任何复制了这个文件的人都能立刻使用它;有了口令,被偷走的文件在口令被猜出之前毫无用处。对于笔记本上的一把密钥,这正是您想要的保护,因为笔记本会被偷,笔记本的备份也会泄露。

口令在实践中几乎不花代价,原因是 ssh-agent。agent 把您解密后的密钥保存在内存里,于是您每个登录会话只需输入一次口令,之后每一次连接都瞬间完成。大多数桌面版 Linux 发行版和 macOS 已经替您运行着一个 agent。用下面的命令把您的密钥加载进去:

ssh-add ~/.ssh/id_ed25519

ssh-add -l 会列出 agent 当前持有的密钥。一点提醒:agent 转发(ssh -A)会让远程服务器在您连接期间借用您的 agent 继续向下一跳认证,所以只对您完全信任的服务器启用它,默认情况下请关闭。

轮换与吊销:笔记本丢失演练

吊销一把普通 SSH 密钥,无非就是从每一台持有它的服务器上删掉它那一行 authorized_keys。没有需要通知的证书颁发机构,也没有需要等待的到期日。那一行一消失,用这把密钥进行的新登录就会失败。

趁现在不是紧急状况,先做一次演练。挑一台服务器,打开 ~/.ssh/authorized_keys,靠注释找到那把密钥。用编辑器删掉那一行,或者按注释把它过滤掉:

grep -v ' laptop$' ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.tmp
mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keys

然后从您刚刚吊销的那台设备确认登录现在会失败,再从另一台设备确认登录仍然可用。请注意一个细节:移除一把密钥并不会关闭已经打开的会话,因为密钥只在登录时被检查。如果您吊销的是一台被偷的设备,还要在服务器上检查 who,结束任何您不认识的会话。

轮换是同一套操作,只是顺序不同:在设备上生成一把新密钥,用 ssh-copy-id 安装它,确认新密钥能登录,然后删掉旧的那一行。当一台设备易主、一把密钥可能已泄露、或者有人离开团队时,就做这件事。跨两台服务器手动做没问题;跨二十台就该交给自动化了,管理多台 Linux 服务器展示了如何把同一份 authorized_keys 状态推送到整个服务器群。

不要做的事

  • 不要在您所有设备之间共用同一把私钥。这会让吊销单独一台被偷设备变得不可能,除非到处替换这把密钥。
  • 不要把私钥提交到 git 仓库,哪怕是私有仓库。自动化扫描器盯着公共仓库,在一次推送后几分钟内就会尝试泄露的密钥,而一个日后转为公开的仓库会泄露它的整段历史。
  • 不要为了让某台服务器能访问另一台服务器,就把您笔记本的私钥上传到那台服务器。请在那台服务器自身上生成一把独立的密钥,并只在需要的地方授权这把密钥。
  • 不要把私钥粘进聊天、邮件或工单。公钥,也就是 .pub 文件,才是唯一可以分享的那一半。

一旦您的密钥能可靠地让您登录,就迈出下一步,关闭密码认证,让针对您服务器的持续猜测彻底无从得逞。为此准备的 drop-in 配置就在在 VPS 上加固 SSH里。

FAQ

SSH 密钥是如何在不发送密码的情况下工作的?

服务器把您的公钥保存在 ~/.ssh/authorized_keys 里。登录时它发出一道问题,您的客户端用私钥对这道问题签名,服务器再用公钥验证签名。私钥从不离开您的设备,所以传输途中没有可拦截的东西,服务器上也没有可重复使用可偷的东西。一台被攻破的服务器只泄露公钥,而公钥无法用来登录任何地方。

我应该在所有服务器上使用同一把 SSH 密钥吗?

在多台服务器上使用同一把密钥是正确的,只要这把密钥留在单独一台设备上。规则是每台设备一把密钥,而不是每台服务器一把:您笔记本的公钥放到笔记本需要访问的每一台服务器上,而台式机有它自己的密钥。这让吊销保持简单,因为丢失一台设备只需从每台服务器上删掉一行可辨认的记录,其他设备照常工作。

.ssh 目录和 authorized_keys 应该设什么权限?

~/.ssh700authorized_keys 以及每一把私钥设 600,并归属于使用它们的那个账户。sshd 默认以 StrictModes yes 运行,所以一个能被您以外任何人写入的文件或主目录,会让它悄无声息地忽略您的密钥,唯一的痕迹就是服务器的认证日志或 journal 里那句 Authentication refused: bad ownership or modes

我如何从服务器上移除一把 SSH 密钥?

在这把密钥被授权的账户里,从 ~/.ssh/authorized_keys 删掉它那一行。靠注释(密钥材料之后的那个标签)找到正确的一行。用这把密钥进行的新登录会立刻失败,但已经打开的会话仍然保持打开,所以如果设备是被偷的,也要结束该设备的任何活动会话。在这把密钥被复制到的每一台服务器上重复这一操作。

我的 SSH 密钥需要设口令吗?

对于笔记本或台式机上的密钥,需要。口令会把密钥文件加密,于是一份被偷或泄露的副本单凭自身毫无用处,而 ssh-agent 意味着您每个会话只需输入一次,而不是每次连接都输入。服务器上供无人值守自动化使用的密钥通常没有口令,因为没有人在场输入它;请通过限制目标账户能做的事来保护这类密钥。