SSH 密钥管理:从生成到 ssh-agent 到硬件 key 三阶段

SSH 密钥是日常运维 / git 协作的基础。新人常踩的坑:

  • 一个 key 用到所有地方
  • 私钥没加密
  • 失去机器后忘了删 key 的服务端授权
  • 多个机器多个 key 没区分

下面是一套实用的 SSH 密钥管理流程。

1. 生成密钥

ssh-keygen -t ed25519 -C 'name@laptop' -f ~/.ssh/id_ed25519
# 提示 passphrase:建议设一个强密码

-t ed25519 推荐;rsa 4096 兼容性最广但比 ed25519 慢。
-C 是注释,写"哪个用户在哪台机器",方便服务端管理识别。

-f 指定文件名。我习惯:

  • ~/.ssh/id_ed25519 个人主密钥(用得最多)
  • ~/.ssh/id_ed25519_work 工作账号
  • ~/.ssh/id_ed25519_github GitHub 专用

2. 一个 key 不要到处用

理由:

  • 一处泄露 → 所有地方都泄露
  • 不同身份混淆(个人 git / 公司 git / VPS)
  • 撤销时全部更新很麻烦

按维度分:

  • 个人 vs 公司
  • 永久机器(笔记本)vs 临时机器(VPS / 开发容器)
  • GitHub / GitLab 各一把(很多 git host 拒绝重复 key)

3. ssh-agent:缓存解锁的私钥

# 启 agent(GNOME / KDE 默认已经起好)
eval $(ssh-agent)

# 加 key(要输 passphrase 一次)
ssh-add ~/.ssh/id_ed25519
ssh-add ~/.ssh/id_ed25519_work

# 看已加载的 key
ssh-add -l
# 256 SHA256:xxx... name@laptop (ED25519)

# 删某个
ssh-add -d ~/.ssh/id_ed25519_work

# 全删(退出前清干净)
ssh-add -D

之后所有 ssh / scp / git 不再要密码。

4. agent 自动启动 + key 自动加载

~/.zshrc~/.bashrc

# 启 ssh-agent 如果没运行
if [ -z "$SSH_AUTH_SOCK" ]; then
    eval $(ssh-agent -s) >/dev/null
fi

# 自动加载尚未加载的 key
if ! ssh-add -l 2>/dev/null | grep -q "$HOME/.ssh/id_ed25519"; then
    ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi

macOS 用 keychain 集成更优雅:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

密码存系统 keychain,重启后自动加载。

5. authorized_keys 服务端

每台机器的 ~/.ssh/authorized_keys 是允许登录的公钥列表。
推送公钥的标准方式:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# 自动追加到 ~user/.ssh/authorized_keys + 设权限

手动方式(如果 ssh-copy-id 不可用):

cat ~/.ssh/id_ed25519.pub | ssh user@server \
  'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'

6. 给授权 key 加限制

服务端 authorized_keys 每行前面可以加 options:

# 只允许从某 IP
from="203.0.113.5" ssh-ed25519 AAAA... user@laptop

# 不允许 shell / 端口转发 / agent forward;只能跑特定命令
command="/usr/local/bin/backup.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA... backup-runner

# 过期时间
expiry-time="20251231" ssh-ed25519 AAAA... contractor

command 限制是给 backup / 监控这种"只跑一个脚本"的服务账号用的。
登录的人开 shell 也只跑这个命令,比开 shell 安全得多。

7. 定期审计

服务端列所有授权 key:

for u in $(cut -d: -f1 /etc/passwd); do
    if [ -f /home/$u/.ssh/authorized_keys ] || [ -f /root/.ssh/authorized_keys ]; then
        echo "=== $u ==="
        cat /home/$u/.ssh/authorized_keys 2>/dev/null
        [ "$u" = "root" ] && cat /root/.ssh/authorized_keys 2>/dev/null
    fi
done

发现陌生 key / 离职同事 key → 立刻删。

8. 服务端 sshd 加固

/etc/ssh/sshd_config

# 禁密码登录(强制只用密钥)
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no

# 禁 root 直接登录
PermitRootLogin prohibit-password
# 或 no(彻底禁)

# 限制允许登录的用户
AllowUsers alice bob deploy
# 或:AllowGroups sshusers

# 减少协议噪音
ListenAddress 0.0.0.0
Port 22

# 客户端不活动时断开
ClientAliveInterval 300
ClientAliveCountMax 2
sudo sshd -t          # 语法检查
sudo systemctl reload ssh

9. 硬件 key(YubiKey / 谷歌 Titan)

最强方案:私钥永远不在磁盘 / 内存上,存硬件芯片:

# 生成 FIDO2 / U2F 密钥(保存在 YubiKey)
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_yubi

# resident key(可以从其它机器恢复)
ssh-keygen -t ed25519-sk -O resident -f ~/.ssh/id_ed25519_yubi

之后每次 ssh 都需要触摸 YubiKey 金属片。

恢复 resident key 到新机器:

ssh-keygen -K
# 把 YubiKey 上所有 resident key 提取到当前目录

私钥本质上是在 YubiKey 里,磁盘文件只是"指针"。丢硬件 = 数字身份废掉
(但攻击者拿不到密钥)。

10. SSH CA(企业规模时)

机器多了,每次给新人加 key 改几百台机器 authorized_keys 不现实。
SSH CA 系统:

  • 一个 CA 私钥签发用户证书(包含 username + 有效期 + 权限)
  • 每台机器 TrustedUserCAKeys = /etc/ssh/ca.pub
  • 用户拿到带签名的临时证书登录,到期失效
# 签发
ssh-keygen -s ca-key -I alice@2026-05 -n alice -V +1d \
  alice_id_ed25519.pub
# 输出 alice_id_ed25519-cert.pub

# 登录时自动用 cert
ssh server   # ssh 会读 cert + key

工具:Vault SSH backend / Smallstep / Teleport / sssd。

踩过的坑

  • 公钥 vs 私钥:*.pub 是公钥可以随便发;没后缀那个是私钥 永远不发
    新手把 id_ed25519 而不是 id_ed25519.pub 贴 GitHub 是经典错误。
  • 私钥权限:必须 600;775 / 644 sshd 会拒绝使用。chmod 600 ~/.ssh/id_*
  • .ssh/authorized_keys 权限:必须 600;目录必须 700。否则 sshd 静默
    忽略整个文件,登录失败查不到原因(auth log 才会有提示)。
  • ssh-agent forwarding(ForwardAgent yes):跳板机 root 用户能拿你的
    key 用,相当于把信任传递给跳板机。除非完全可信,否则用 ProxyJump
    代替 agent forward。
精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。