authorizedkeyscommand 是 openssh 动态获取公钥的机制,需配置 authorizedkeyscommanduser、确保脚本输出合规、禁用本地 authorized_keys 文件,并注意权限、selinux 和审计日志。

AuthorizedKeysCommand 是 OpenSSH 提供的机制,用于在用户登录时**动态获取公钥**,而不是从固定的 ~/.ssh/authorized_keys 文件读取。这特别适合集中管理密钥的场景,比如把公钥存在数据库、GitLab、Vault 或自建 API 中——实现“一次录入、多机生效、实时审计”。
配置 AuthorizedKeysCommand 的核心要点
关键不是写个脚本就完事,而是确保整个链路权限、格式、上下文都正确:
-
必须显式指定 AuthorizedKeysCommandUser:sshd 默认以 root 运行该命令,但你的密钥查询逻辑(比如查数据库或读用户专属目录)通常依赖登录用户名
$1,且不能越权访问敏感路径。应在/etc/ssh/sshd_config中设置:AuthorizedKeysCommand /usr/local/bin/fetch-keys.sh<br>AuthorizedKeysCommandUser ssh-keymgr
-
脚本输出必须严格合规:每行一个完整公钥,以
ssh-rsa、ssh-ed25519等开头,末尾**不能有空格、制表符或多余换行**。可用printf "%s\n" "$key" | tr -d '\r\n ' | grep -E '^(ssh-rsa|ssh-ed25519) '做清洗。 -
拒绝共享 authorized_keys 文件:动态模式下,
~/.ssh/authorized_keys应被忽略或留空。所有密钥由命令统一供给,避免本地文件覆盖云端策略。
一个安全可用的 fetch-keys.sh 示例
假设你用轻量 HTTP 服务托管密钥(如 Flask + SQLite),脚本可这样设计:
- 开头加
set -euo pipefail,防止$1(用户名)为空时静默失败; - 用
curl -s "https://keys.example.com/v1/pubkey?user=$1"获取; - 校验返回状态码和内容类型,只接受
text/plain; - 用
awk '{print}'清理空白行,再用head -n1限制最多返回一条(防误配); - 记录日志到
/var/log/ssh-keys.log,含时间戳、用户名、是否命中。
权限与 SELinux 注意事项
常见失败不是逻辑错,而是环境卡住:
-
目录与脚本权限:脚本本身需可被
ssh-keymgr用户执行(如chmod 750 /usr/local/bin/fetch-keys.sh,属主为 root:ssh-keymgr); -
SELinux 上下文:若启用 SELinux,脚本需打上
ssh_exec_t标签:chcon -t ssh_exec_t /usr/local/bin/fetch-keys.sh; -
systemd-run 隔离调用(可选增强):在脚本内用
systemd-run --scope --uid=ssh-keymgr --gid=ssh-keymgr curl ...,进一步限制网络调用的用户上下文。
审计与故障排查技巧
动态加载一旦出问题,登录直接被拒,且错误提示模糊(常显示 “Authentication refused”)。建议:
- 手动模拟调用:
sudo -u ssh-keymgr /usr/local/bin/fetch-keys.sh testuser,看输出是否干净; - 检查
/var/log/secure或journalctl -u sshd -n 50,搜索AuthorizedKeysCommand相关日志; - 密钥记录中存创建时间和最后使用时间,例如在数据库里加
created_at和last_used字段,便于事后追溯; - 首次部署时,在
sshd_config中临时加LogLevel VERBOSE,重启后观察详细流程。










