如何在 macOS 或 Linux 上使用 OpenSSH 创建 SSH 密钥
SSH 基于密钥的身份验证是保护远程服务器访问的行业标准方法。您的客户端无需通过网络传输密码,而是通过解决一个只有私钥持有者才能回答的密码学挑战来证明其身份——服务器永远不会看到私钥本身。
一个 SSH 密钥对由两个数学上相互关联的文件组成:私钥(仅存储在您的本地计算机上,从不共享)和公钥(部署到您需要访问的每台服务器上)。当您发起连接时,OpenSSH 使用挑战-响应握手来验证您的私钥是否与服务器上的公钥对应,从而无需密码提示即可授予访问权限。
为什么 SSH 密钥严格优于密码身份验证
密码容易受到暴力破解攻击、凭据填充、网络钓鱼以及在配置不当的网络上被拦截。SSH 密钥可同时消除所有这些攻击向量。
- 密码学强度:4096 位 RSA 密钥或 Ed25519 密钥在计算上无法用当前硬件进行暴力破解。
- 无秘密通过网络传输:私钥永远不会离开您的计算机。身份验证协议在不披露的情况下证明持有权。
- 适合自动化:CI/CD 流水线、Ansible playbook、rsync 任务和基于 cron 的备份都需要非交互式身份验证。SSH 密钥使这一切成为可能,无需在脚本中嵌入明文密码。
- 可审计性:每个密钥对都可以通过其指纹唯一标识,使得在不需要到处轮换凭据的情况下,撤销单个受损密钥变得简单直接。
- 与
authorized_keysACL 的兼容性:您可以限制特定公钥只运行一个命令、将其绑定到源 IP,或阻止端口转发——这些控制是密码身份验证无法复制的。
如果您正在管理 VPS 或独立服务器,完全禁用密码身份验证并强制执行仅密钥登录是您可以采取的影响最大的安全加固步骤之一。
选择正确的密钥算法
原始 OpenSSH 文档和大多数旧版教程默认使用 RSA。该领域已经有所进展。以下是 ssh-keygen 目前支持的每种算法的精确比较:
| 算法 | 密钥大小 | 安全级别 | 速度 | 推荐使用场景 |
|---|---|---|---|---|
| — | — | — | — | — |
| **Ed25519** | 固定 256 位 | ~128 位等效 | 最快 | 所有新密钥的默认选择 |
| **ECDSA** | 256 / 384 / 521 位 | 128–260 位等效 | 快 | 当 Ed25519 不可用时(旧版服务器) |
| **RSA** | 2048–4096 位 | 112–140 位等效 | 较慢 | 与非常旧的 SSH 守护进程兼容 |
| **DSA** | 固定 1024 位 | 已破解 | 不适用 | 请勿使用——在 OpenSSH 7.0+ 中已弃用 |
Ed25519 是 2024 年的正确默认选择。它生成更短的密钥,签名更快,其固定密钥大小消除了意外生成过小密钥的风险。4096 位的 RSA 对于必须与早于 Ed25519 支持的旧系统(OpenSSH < 6.5,发布于 2014 年)互操作的环境仍然可以接受。
前提条件
- 安装了 OpenSSH 的 macOS 或 Linux 工作站。两种操作系统默认都附带 OpenSSH。使用以下命令验证:
ssh -V- 可以通过网络访问您拥有账户(root 或非特权账户)的远程服务器。
- 对终端有基本的熟悉程度。
在附带最小安装的 Linux 发行版(Alpine、某些 Debian 网络安装版)上,使用以下命令安装客户端工具:
# Debian / Ubuntu
sudo apt install openssh-client
# RHEL / CentOS / AlmaLinux / Rocky
sudo dnf install openssh-clients第 1 步:打开终端
macOS:按 Cmd + Space,输入 Terminal,然后按 Enter。或者,导航到”应用程序”>”实用工具”>”终端”。高级用户可以使用 iTerm2 或 VS Code 中的内置终端。
Linux:在大多数桌面环境中按 Ctrl + Alt + T,或从应用程序菜单启动您的发行版终端模拟器。
第 2 步:生成 SSH 密钥对
生成 Ed25519 密钥(推荐)
ssh-keygen -t ed25519 -C "your_email@example.com"-C 标志会在公钥中附加一个人类可读的注释。使用您的电子邮件地址、主机名或描述性标签(如 "deploy-key-prod")——它没有密码学功能,但在审计积累了数十个条目的 authorized_keys 文件时非常有价值。
生成 RSA 密钥(旧版兼容性)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"明确使用 -b 4096。2048 位的历史默认值在技术上仍然可以接受,但对于因式分解算法未来的进步提供的余量较少。如果 4096 可用,新密钥切勿使用 -b 1024 或 -b 2048。
为特定主机生成命名密钥
在管理多台服务器或角色时,使用不同的密钥文件,而不是在任何地方重复使用一个密钥。这样,受损的密钥只会影响其部署到的系统:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_prod_webserver -C "prod-webserver-2024"第 3 步:选择存储位置
运行 ssh-keygen 后,您将看到:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/youruser/.ssh/id_ed25519):按 Enter 接受默认值(Ed25519 为 ~/.ssh/id_ed25519,RSA 为 ~/.ssh/id_rsa),或输入自定义路径。默认位置适用于单个通用密钥。对于特定角色的密钥,始终按照上一步所示指定描述性文件名。
关键文件权限说明:~/.ssh/ 目录必须为 700 模式,私钥文件必须为 600 模式。OpenSSH 将拒绝使用权限过于宽松的密钥并打印警告。如果您曾在计算机之间复制密钥,请立即验证权限:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub第 4 步:设置密码短语
Enter passphrase (empty for no passphrase):
Enter same passphrase again:密码短语使用 AES-256-CBC(在现代 OpenSSH 中)对磁盘上的私钥文件进行加密。如果攻击者获取了您的私钥文件——通过被盗的笔记本电脑、受损的备份或配置错误的云快照——强密码短语是阻止他们使用它的最后一道防线。
何时跳过密码短语:无人值守运行的自动化服务账户(部署流水线、备份代理)合理地需要无密码短语的密钥。在这种情况下,使用 authorized_keys 选项在服务器端限制密钥的权限(见下面的高级部分),并将私钥存储在密钥管理器中,而不是共享文件系统上。
确认密码短语后,OpenSSH 输出密钥指纹和随机艺术图像:
Your identification has been saved in /home/youruser/.ssh/id_ed25519
Your public key has been saved in /home/youruser/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abc123XYZexampleFingerprint your_email@example.com
The key's randomart image is:
+--[ED25519 256]--+
| .o+. |
...
+----[SHA256]-----+记录指纹。在审计服务器时,您将使用它来验证密钥的身份。
第 5 步:将公钥复制到远程服务器
方法 1:ssh-copy-id(最快)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server.com-i 标志明确指定要复制哪个公钥,防止 ssh-copy-id 上传代理中的每个密钥。您将被提示输入一次服务器密码。该工具自动处理目录创建、文件追加和权限设置。
方法 2:手动部署(当 ssh-copy-id 不可用时)
当远程系统是 Windows、网络设备或路径中没有 ssh-copy-id 的容器时,这是正确的方法。
首先,显示您的公钥:
cat ~/.ssh/id_ed25519.pub复制整个输出——它是以 ssh-ed25519(或 ssh-rsa)开头的单行。然后登录服务器并追加它:
ssh user@your-server.com连接后:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "ssh-ed25519 AAAA...your-full-public-key... your_email@example.com" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys常见陷阱:使用 > 而不是 >> 会覆盖整个 authorized_keys 文件,锁定所有其他密钥。始终使用 >> 进行追加。
方法 3:通过 SSH 用一个命令管道传输
如果您已经有密码访问权限,并希望在不交互式登录的情况下进行部署:
cat ~/.ssh/id_ed25519.pub | ssh user@your-server.com "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"第 6 步:测试连接
ssh -i ~/.ssh/id_ed25519 user@your-server.com成功连接而没有密码提示(或仅有本地密钥的密码短语提示)确认设置正确。如果连接失败,请使用详细输出运行以进行诊断:
ssh -vvv -i ~/.ssh/id_ed25519 user@your-server.com-vvv 标志打印完整的协商日志,显示提供了哪个密钥、服务器是否接受它,以及握手在哪里失败。
第 7 步:配置 ~/.ssh/config 以实现持久主机配置文件
每次输入完整的 ssh -i ~/.ssh/id_ed25519_prod_webserver user@203.0.113.45 容易出错且速度慢。SSH 客户端配置文件消除了这一问题:
nano ~/.ssh/config添加主机块:
Host prod-web
HostName 203.0.113.45
User deploy
IdentityFile ~/.ssh/id_ed25519_prod_webserver
Port 2222
ServerAliveInterval 60现在只需以下命令连接:
ssh prod-web这种模式可以干净地扩展到数十台服务器,对于任何大规模管理基础设施的工程师来说都是必不可少的。ServerAliveInterval 60 指令每 60 秒发送一个保活数据包,防止空闲连接被防火墙断开——这是云提供商上常见的令人沮丧的问题。
使用 SSH 代理管理多个密钥
SSH 代理在您的会话期间将解密的私钥保存在内存中,因此您只需输入一次密码短语,而不是每次连接都输入。
启动代理并添加密钥:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519在 macOS 上,您可以通过将以下内容添加到 ~/.ssh/config 来在重启后持久保存密钥:
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519UseKeychain yes 指令与 macOS 钥匙串集成,安全地存储密码短语,使其在系统重启后仍然有效。
列出代理中当前加载的所有密钥:
ssh-add -l从代理中删除特定密钥:
ssh-add -d ~/.ssh/id_ed25519高级:在 authorized_keys 中限制密钥
authorized_keys 文件支持每个密钥的选项,可以显著减少受损密钥的影响范围。这些选项放置在同一行的密钥类型之前:
command="/usr/bin/rsync --server ...",no-pty,no-agent-forwarding,no-port-forwarding ssh-ed25519 AAAA... backup-key| 选项 | 效果 |
|---|---|
| — | — |
| `command="…"` | 强制只执行特定命令;忽略客户端请求的内容 |
| `no-pty` | 阻止分配交互式终端 |
| `from="203.0.113.0/24"` | 将密钥使用限制为来自特定 IP 范围的连接 |
| `no-port-forwarding` | 阻止通过此密钥进行 TCP 隧道传输 |
| `expiry-time="20251231"` | 密钥在指定日期后自动停止工作(OpenSSH 8.2+) |
这些选项对于独立服务器上的部署密钥特别有价值,在这些服务器上,单个受损的 CI/CD 密钥不应授予完整的 shell 访问权限。
密钥部署后加固 SSH 守护进程
一旦基于密钥的身份验证正常工作,请在服务器上完全禁用密码身份验证。编辑 /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config设置以下指令:
PasswordAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin prohibit-password
AuthenticationMethods publickey在不断开当前会话的情况下重新加载守护进程:
sudo systemctl reload sshd在单独的终端中测试新连接之前,请勿关闭现有的 SSH 会话。将您锁定在外的错误配置可以从控制台恢复,但这会造成干扰且是可以避免的。
对于运行 cPanel VPS 环境的服务器,请注意某些 cPanel 版本管理其自己的 SSH 配置。通过检查 /etc/ssh/sshd_config.d/ 中的覆盖文件,验证 sshd_config 更改在 cPanel 更新后是否持久。
轮换和撤销 SSH 密钥
密钥轮换是一种安全卫生实践,可以限制密钥被悄悄泄露时的暴露窗口。实际的轮换计划是个人密钥每 12 个月一次,服务账户密钥每 90 天一次。
撤销密钥:从其部署到的每台服务器上的 ~/.ssh/authorized_keys 中删除其对应行。标准 OpenSSH 中没有中央撤销机制——这就是为什么维护每个密钥指纹部署位置的清单很重要。
轮换密钥:
- 生成新的密钥对。
- 将新公钥部署到所有目标服务器。
- 使用新密钥测试连接。
- 从所有
authorized_keys文件中删除旧公钥。 - 在本地删除或归档旧私钥。
对于跨多个区域拥有 VPS 托管的环境,像 Ansible 这样的配置管理工具是大规模传播密钥轮换的实用解决方案。
在计算机之间传输密钥
当您设置新工作站时,您需要迁移现有的私钥,而不是生成新的私钥(这需要在所有地方重新部署公钥)。
使用 scp 或 rsync 通过 SSH 安全复制私钥:
scp ~/.ssh/id_ed25519 newmachine.local:~/.ssh/id_ed25519或者,使用加密的 USB 驱动器或支持 SSH 密钥存储的密码管理器(1Password、Bitwarden 和 HashiCorp Vault 都支持此功能)。切勿通过电子邮件发送私钥或将其存储在未加密的云存储中。
传输后,立即验证新计算机上的权限:
chmod 600 ~/.ssh/id_ed25519验证服务器的主机密钥指纹
第一次连接到服务器时,OpenSSH 会显示服务器的主机密钥指纹并要求您确认:
The authenticity of host '203.0.113.45 (203.0.113.45)' can't be established.
ED25519 key fingerprint is SHA256:abc123XYZexample.
Are you sure you want to continue connecting (yes/no/[fingerprint])?切勿盲目输入 yes。通过带外渠道获取预期指纹——您的托管提供商的控制面板、配置服务器的同事,或服务器的控制台输出。此步骤可防止中间人攻击。对于共享托管环境,预期指纹通常列在控制面板的 SSH 访问设置下。
一旦接受,指纹将存储在 ~/.ssh/known_hosts 中。如果在后续连接中指纹意外更改,OpenSSH 将拒绝连接并显示警告——在继续之前,将此视为需要调查的严重安全事件。
决策矩阵和技术检查清单
在认为您的 SSH 密钥设置可以投入生产之前,请使用此检查清单:
- [ ] 密钥算法为 Ed25519(或 RSA 4096 用于旧版兼容性)——DSA 和 ECDSA 256 不适用于新部署
- [ ] 私钥文件权限为
600;~/.ssh/目录权限为700 - [ ] 所有交互式用户密钥都设置了强密码短语
- [ ] 没有密码短语的服务账户密钥通过
authorized_keys选项(command=、from=、no-pty)进行了限制 - [ ] 所有服务器的
/etc/ssh/sshd_config中设置了PasswordAuthentication no - [ ] 强制执行了
PermitRootLogin prohibit-password或PermitRootLogin no - [ ] 服务器主机密钥指纹已通过带外方式验证
- [ ] 存在密钥清单,将每个指纹映射到其部署的服务器
- [ ] 已定义并安排了密钥轮换计划
- [ ] 配置了
~/.ssh/config主机块,以避免手动使用-i标志 - [ ] 使用 SSH 代理以避免在工作会话期间重复输入密码短语
- [ ] 定期审查
known_hosts条目,检查过时或意外的条目
常见问题
Ed25519 和 RSA SSH 密钥有什么区别?
Ed25519 使用椭圆曲线密码学,具有固定的 256 位密钥,提供约 128 位的安全性,签名操作比 RSA 更快,并生成更短的密钥字符串。4096 位的 RSA 提供相当的安全性,但速度较慢且生成更大的密钥材料。除非您必须连接到运行 OpenSSH 6.5 以下版本的系统,否则所有新密钥都应使用 Ed25519。
我可以对多台服务器使用同一个 SSH 密钥对吗?
技术上可以。但是,最佳实践是为每个角色或环境使用不同的密钥对(个人工作站访问、CI/CD 部署、数据库维护)。这限制了单个受损密钥的影响,并使撤销变得简单直接,而不会干扰不相关的系统。
如果我丢失了私钥会怎样?
您将失去使用该密钥对进行身份验证的能力。服务器上的公钥将变得无用。您必须通过替代方法访问服务器——控制台访问、辅助密钥或您的托管提供商的紧急访问——然后从 authorized_keys 中删除孤立的公钥并部署新的密钥对。
为什么复制公钥后 SSH 仍然要求输入密码?
最常见的原因是:服务器上 ~/.ssh/(必须为 700)或 ~/.ssh/authorized_keys(必须为 600)的权限不正确;主目录本身具有全局写入权限;SELinux 或 AppArmor 阻止访问 .ssh 目录;或者 /etc/ssh/sshd_config 中设置了 PubkeyAuthentication no。运行 ssh -vvv 以准确识别正在尝试和拒绝哪种身份验证方法。
如何从我不再有访问权限的服务器上删除 SSH 密钥?
如果您没有其他身份验证方法,请联系您的托管提供商的支持团队,或使用带外控制台访问(适用于 VPS 和独立服务器客户)登录并直接编辑 ~/.ssh/authorized_keys。这就是为什么将控制台访问凭据与 SSH 密钥分开维护是不可妥协的操作要求。
