根本原因是服务端未启用证书验证或ca公钥配置错误:sshd_config须设trustedusercakeys指向权限644的ca公钥,且私钥与公钥严格配对,证书必须含-i标识和-n指定用户名,时钟偏差超5分钟亦会导致失败。

为什么 ssh-keygen -s 签发的证书不被服务器接受
根本原因通常是服务端没启用证书验证,或 CA 公钥没放对位置。OpenSSH 要求服务器明确信任某个 CA,不是“签了就能用”。
-
sshd_config必须包含TrustedUserCAKeys /etc/ssh/ca.pub(路径可变,但必须指向 CA 的公钥文件) - 该公钥文件权限必须是
644,且属主为root;/etc/ssh/目录不能有写权限给组或其他人 - 签发证书时用的 CA 私钥和此处配置的公钥必须严格配对——用
ssh-keygen -L -f user-cert.pub可确认证书里嵌入的 CA 指纹是否匹配 - 重启
sshd后,日志(journalctl -u sshd)里出现debug1: userauth-request for user xxx [preauth]之后没提证书相关 log,基本就是 CA 配置未生效
用户证书怎么生成才支持自动登录和命令限制
靠 ssh-keygen -s 签发时加参数控制行为,不是靠客户端配置。证书本身得带身份和策略信息,服务端才认。
- 必加
-I指定唯一标识(如dev-001),否则sshd拒绝认证(日志报no key ID in certificate) - 用
-n指定允许登录的用户名或逗号分隔列表(如-n "alice,bob"),空值或错写会导致认证失败 - 加
-O force-command="/usr/bin/restricted-shell"可锁定命令,但注意:该命令必须存在于目标用户 shell PATH 中,且不能依赖交互式环境变量 - 有效期用
-V(如-V +52w),别用绝对时间戳——本地和服务端时钟偏差超 5 分钟就会拒掉证书
ssh-add -s 加载 PKCS#11 模块失败的常见原因
这不是 SSH 证书问题,而是智能卡或硬件密钥场景下加载签名模块出错。错误通常出现在客户端侧,和 CA 无关但常被混淆。
- 模块路径写错:
ssh-add -s /usr/lib/opensc-pkcs11.so—— 不同系统路径不同(Ubuntu 是/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so) - 缺少依赖库:运行
ldd /path/to/module.so | grep "not found"能快速定位缺哪个.so - 权限不足:如果模块访问 USB 设备(如 YubiKey),当前用户需在
dialout或plugdev组里,且 udev 规则已加载 -
ssh-add -s成功后不会输出任何内容,只在失败时打印错误;用ssh-add -l查看是否真加载了 PKCS#11 key
自动化部署 CA 证书时最易忽略的权限与路径细节
批量下发 CA 公钥到上百台机器时,脚本往往只管复制文件,却漏掉 OpenSSH 极其敏感的权限链。
-
TrustedUserCAKeys配置里的路径,必须是绝对路径,且不能是符号链接(OpenSSH 会拒绝加载) - CA 公钥文件本身不能有 group/others 写权限,否则
sshd启动时静默忽略该行配置(查sshd -T | grep ca输出为空即中招) - 如果用 Ansible,别直接
copy到/etc/ssh/—— 先file模块确保目录权限为755,再设文件权限为644,最后systemd restart sshd - 证书吊销不靠文件删除,而要配
RevokedKeys /etc/ssh/revoked-keys并定期更新该文件——这点几乎没人做,但生产环境必须考虑
TrustedUserCAKeys 文件是否真正被 sshd 读进去、以及证书里 -I 和 -n 的值是否和服务端策略严丝合缝。差一个字符,就只能看到 Permission denied (publickey)。










