SSH 证书认证实战:用 SSH CA 替代长期密钥

适用场景

服务器数量增长到几十台以上后,传统「把公钥塞进每台机器 authorized_keys」的运维方式会暴露三个问题:人员离职后密钥清理不彻底、密钥无有效期一旦泄露长期可用、新机器上线需要逐台分发公钥。SSH 证书认证通过引入一个自建 CA(Certificate Authority),用短期证书替代长期密钥,把「每台机器授权」改为「CA 一次性签发」,是规模化 SSH 访问治理的标准做法。本文适用于运维团队、云主机集群、跳板机与 CI/CD 发布账号的 SSH 登录改造。

前置条件

  • OpenSSH 版本不低于 6.5(证书认证自该版本引入),推荐 8.x 以上;执行 ssh -V 确认
  • 至少两台 Linux 主机,一台作为证书签发机(可离线),其余作为目标服务器
  • 目标服务器 sshd 配置文件路径 /etc/ssh/sshd_config,具备 root 或 sudo 权限
  • 各主机系统时间同步(chrony 或 ntpd),证书校验强依赖时间

原理说明

SSH 证书认证的核心是把信任锚点从「每台服务器的 authorized_keys 列表」上移到一个 CA 公钥。目标服务器只需在 sshd 中配置 TrustedUserCAKeys 指向 CA 公钥,此后任何由该 CA 私钥签发、且在有效期与 principal(主体名)范围内的证书,都可直接登录,无需在服务器上保留任何用户公钥。

  • 签发者对用户 → User CA:用于签发用户登录证书(-s user_ca)
  • 签发者对主机 → Host CA:用于签发服务器主机证书(-h),客户端借此免除首次连接时的指纹确认
  • 证书包含字段:Key ID(-I)有效期(-V)主体名(-n)序列号来源限制(-O),可随时通过 KRL(Key Revocation List)吊销

操作步骤

1. 生成 CA 密钥对

在签发机上创建用户 CA 与主机 CA,私钥权限必须为 600 且不入库、不随代码分发。

sudo mkdir -p /etc/ssh/ca && sudo chmod 700 /etc/ssh/ca
sudo ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca -C "user-ca" -N ""
sudo ssh-keygen -t ed25519 -f /etc/ssh/ca/host_ca -C "host-ca" -N ""
sudo chmod 600 /etc/ssh/ca/user_ca /etc/ssh/ca/host_ca
ls -l /etc/ssh/ca/

参数说明:-t ed25519 指定密钥算法;-N “” 表示空密码短语(便于自动化签发,但私钥文件本身必须严格保护)。

2. 目标服务器信任用户 CA

把 user_ca.pub 分发到各服务器的 /etc/ssh/ 目录,并在 sshd_config 中声明信任。

# 在每台目标服务器执行
sudo scp ca_server:/etc/ssh/ca/user_ca.pub /etc/ssh/user_ca.pub
sudo tee -a /etc/ssh/sshd_config >/dev/null <<'EOF'

# SSH 证书认证
TrustedUserCAKeys /etc/ssh/user_ca.pub
EOF
sudo sshd -t && sudo systemctl reload sshd

如需要求证书主体名必须存在于系统账户,可追加 AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u,在对应文件中写入允许的 principal 列表(每行一个)。

3. 签发用户登录证书

用户生成密钥对后把公钥交给 CA 签发,证书有效期建议 8 小时至 7 天

# 用户侧:生成密钥对
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "alice" -N ""
# 把 id_ed25519.pub 提交给 CA(如通过工单或内部平台)

# CA 侧:签发证书,有效期 8 小时,主体名 alice
sudo ssh-keygen -s /etc/ssh/ca/user_ca \
  -I "alice@corp-20260911" \
  -n alice \
  -V +8h \
  -O clear_allow_extensions \
  /tmp/alice.pub
# 产出 /tmp/alice-cert.pub,回传给用户

关键参数:-I 为 Key ID(写入日志,便于审计);-n 为允许的登录主体名,多个用逗号分隔;-V +8h 为相对有效期,也可写绝对时间 -V 20260911:20260912

用户把证书放到私钥同目录并命名为 <私钥名>-cert.pub,sshd 会自动加载:

mv alice-cert.pub ~/.ssh/id_ed25519-cert.pub
ssh alice@web01.example.com

4. 签发主机证书(可选但强烈推荐)

# 目标服务器上签发自身主机证书,有效期 52 周
sudo ssh-keygen -s /etc/ssh/ca/host_ca \
  -I "host-web01" -h \
  -n web01.example.com,10.0.0.11 \
  -V +52w \
  /etc/ssh/ssh_host_ed25519_key.pub

sudo tee -a /etc/ssh/sshd_config >/dev/null <<'EOF'
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
EOF
sudo sshd -t && sudo systemctl reload sshd

# 客户端 known_hosts 声明主机 CA,免除逐台指纹确认
echo "@cert-authority *.example.com $(cat /etc/ssh/ca/host_ca.pub)" >> ~/.ssh/known_hosts

配置验证

查看证书内容,确认主体名、有效期与用途正确:

ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub

验证 sshd 已加载信任的 CA:

sudo sshd -T | grep -i trustedusercakeys
# 预期输出:trustedusercakeys /etc/ssh/user_ca.pub

登录时观察服务器认证日志,应出现证书认证成功记录:

sudo journalctl -u ssh -n 20 | grep -i "Accepted publickey"
# 预期包含:Accepted publickey for alice ... ED25519-CERT SHA256:...

客户端调试可用:ssh -vvv alice@web01.example.com,在输出中检索 Offering public keyServer accepts key 两行。

常见问题

FAQ 1:证书认证后,原来的 authorized_keys 公钥登录还能用吗?

可以,两者并行不冲突。sshd 会先按证书认证处理,失败后回退到 authorized_keys。改造期间建议保留原公钥,待全部用户切换证书后,再通过 AuthorizedKeysFile none 关闭公钥认证以强制证书登录。注意该指令会同时禁用无证书的密钥登录,务必确认证书链路已完全可用再修改。

FAQ 2:证书明明未过期,为什么登录报「Permission denied (publickey)」?

按以下顺序排查:

  • 证书文件名:必须为私钥名后加 -cert.pub,否则 ssh 不会自动加载,需用 -i 显式指定
  • 时间偏差:证书校验基于时间,客户端或服务器任一方的时钟误差超过有效期窗口即失败。执行 timedatectl status 检查同步状态
  • principal 不匹配:登录用户名必须落在证书的 -n 列表中,或存在于 AuthorizedPrincipalsFile
  • 服务器未信任 CA:确认 TrustedUserCAKeys 路径正确且文件可读,reload 后生效

定位最直接的方式是客户端 ssh -vvv 与服务器端 sudo /usr/sbin/sshd -ddd -p 2222 双端对照日志。

FAQ 3:如何撤销一张已签发但未过期的证书?

SSH 证书无法单独撤销,但由于采用短期有效期,通常等待过期即可。若需立即吊销,使用 KRL(Key Revocation List):

# CA 侧生成吊销列表
sudo ssh-keygen -k -f /etc/ssh/ca/revoked_keys -s /etc/ssh/ca/user_ca /tmp/alice.pub
# 目标服务器加载
sudo tee -a /etc/ssh/sshd_config >/dev/null <<'EOF'
RevokedKeys /etc/ssh/revoked_keys
EOF
sudo sshd -t && sudo systemctl reload sshd

已撤销的证书在 KRL 生效后立即失效,ssh -vvv 中可见 key revoked 提示。

总结

SSH 证书认证把「逐台分发公钥」变成「CA 统一签发」,收益集中在三点:短期有效把密钥泄露的时间窗口从永久压缩到数小时;集中吊销用 KRL 一次性失效;可审计通过 Key ID 把每次登录关联到具体签发记录。落地建议按顺序推进:先建主机 CA 消除指纹确认,再建用户 CA 并保留原公钥并行运行,最后关闭公钥认证强制证书登录。CA 私钥必须离线保存或放入硬件模块,一旦泄露等同于全部服务器失守。