必须指定非root用户执行authorizedkeyscommand,如ssh-keymgr;脚本需校验输入、清洗输出、按用户名精确查询统一密钥源,并记录日志、追加溯源注释、禁用本地密钥文件。

要用 AuthorizedKeysCommand 加载统一的、动态的、非 root 身份公钥,核心不是“绕过 root”,而是**让 SSH 服务以普通用户身份安全执行查询逻辑**,并确保整个链路不越权、不泄露、可审计。OpenSSH 9.6p1(Ubuntu 24.04 默认)起已默认以 sshd 用户而非 root 调用该命令,所以显式配置 AuthorizedKeysCommandUser 不再是建议,而是必须。
必须指定非 root 执行用户
sshd 默认不再以 root 运行你的命令脚本,但旧脚本若依赖 sudo 或硬编码路径仍会失败。你得主动创建专用低权限用户,并在配置中锁定上下文:
- 新建系统用户:
sudo adduser --disabled-password --gecos "" ssh-keymgr - 在
/etc/ssh/sshd_config中添加两行:AuthorizedKeysCommand /usr/local/bin/fetch-key.shAuthorizedKeysCommandUser ssh-keymgr - 脚本属主必须是
ssh-keymgr,且权限设为755;不能被组或其他人写入
脚本必须严格校验输入与输出
脚本接收的 是登录用户名,它可能为空、含特殊字符或被恶意构造。输出则必须是一行标准公钥,多一个空格或换行都会导致认证拒绝:
- 开头加
set -euo pipefail,防止$1为空时静默继续 - 用
printf "%s" "$key" | sed 's/[[:space:]]*$//' | grep -E '^(ssh-rsa|ssh-ed25519|ecdsa-sha2-nistp)'清洗并校验格式 - 禁止输出空行、注释、JSON 包裹体;若从 API 获取,需用
jq -r '.pubkey'或awk 'NR==1'提取首行
从统一源拉取,但隔离每个用户权限
所谓“统一动态”,是指密钥集中托管(如 Vault、PostgreSQL、S3),但查询逻辑必须按 $1 精确限定范围,避免跨用户访问:
- 查数据库:用专用只读账号连接,SQL 语句带
WHERE username = $1,禁用拼接,改用参数化查询(如psql -U key_reader -c "SELECT pubkey FROM keys WHERE username = $1") - 查对象存储:路径固定为
s3://my-keys-bucket/pubkeys/$1.pub,不支持通配符或目录遍历 - 调用 HTTP 接口:URL 中仅传
$1,Header 带短期有效的 bearer token,后端做 RBAC 鉴权
安全加固与行为留痕不可省略
动态加载放大了风险面,每一步都要留痕、限权、可追溯:
- 脚本日志写入
/var/log/ssh-key-fetch.log,记录时间、用户名、HTTP 状态码、公钥指纹(ssh-keygen -lf /dev/stdin ) - 所有返回的公钥末尾追加注释,例如:
# from vault-v2@2026-05-29T02:45:11Z - SELinux 环境下,给脚本打标签:
sudo semanage fcontext -a -t ssh_exec_t "/usr/local/bin/fetch-key.sh",再restorecon - 禁用本地
~/.ssh/authorized_keys,确保所有认证完全走动态路径,不留后门











