AuthorizedKeysCommand 是 OpenSSH ≥6.1 服务端动态获取公钥的机制,通过配置外部脚本对接API/数据库,需设AuthorizedKeysCommandUser为非root用户并确保权限安全。

AuthorizedKeysCommand 是 OpenSSH 服务端的一项高级配置功能,允许 SSH 守护进程(sshd)在用户尝试登录时,动态调用外部程序获取其公钥,而不是从固定的 ~/.ssh/authorized_keys 文件中读取。这适用于需要集中管理密钥、对接 LDAP/AD(需自定义逻辑)、数据库或 Web API 的场景。
注意前提:该功能 仅在服务端启用,且要求 OpenSSH 版本 ≥ 6.1(主流 Linux 发行版默认满足),但 Windows OpenSSH 不支持(Microsoft Learn 明确指出不支持 AuthorizedKeysCommand 和 AuthorizedKeysCommandUser 指令)。
一、服务端配置与基础要求
在 SSH 服务端(通常是目标服务器)的 /etc/ssh/sshd_config 中添加以下两行:
AuthorizedKeysCommand /usr/local/bin/fetch-pubkey.sh %u %hAuthorizedKeysCommandUser nobody
说明:
-
%u会被替换成正在登录的用户名;%h是该用户的家目录路径(如/home/alice),可用于日志或权限判断。 - 脚本必须由
AuthorizedKeysCommandUser指定的用户(推荐nobody或专用低权用户)执行,不能是 root —— 这是安全强制要求。 - 脚本路径必须可被该用户执行,且整个路径上的目录权限不能过于宽松(例如不能有 world-writable 目录)。
- 修改后需重启服务:
sudo systemctl restart sshd(或sshd)。
二、编写获取公钥的脚本(以 Bash + curl 调用 API 为例)
创建脚本 /usr/local/bin/fetch-pubkey.sh,内容如下:
#!/bin/bash set -u <h1>接收参数:用户名和家目录(实际中可能只用到 $1)</h1><p>USERNAME="$1"</p><h1>示例:向内部 REST API 发起 GET 请求,返回纯文本公钥(一行,以 ssh-rsa/ssh-ed25519 开头)</h1><h1>替换为你的真实 API 地址和认证方式(如 API token、mTLS 等)</h1><p>API_URL="<a href="https://www.php.cn/link/5b2b90013bf899246dfdfd063813e999">https://www.php.cn/link/5b2b90013bf899246dfdfd063813e999</a>" API_TOKEN="Bearer abc123def456"</p><h1>使用最小依赖调用(避免 bash 太重),超时 3 秒</h1><p>KEY=$(curl -s -f -m 3 -H "Authorization: $API_TOKEN" "$API_URL" 2>/dev/null)</p><h1>仅当返回非空、格式合法的公钥时才输出(防止空响应导致认证失败)</h1><p>if [[ -n "$KEY" ]] && [[ "$KEY" =~ ^ssh-[a-z0-9]+\ [A-Za-z0-9+/]+[=]* ]]; then printf "%s\n" "$KEY" fi</p>
然后赋予执行权限并设置属主:
sudo chmod 755 /usr/local/bin/fetch-pubkey.shsudo chown root:root /usr/local/bin/fetch-pubkey.sh
三、关键安全与可靠性要点
-
网络与认证安全:API 必须使用 HTTPS,且脚本中 token 应避免硬编码;推荐改用文件挂载(如
/run/secrets/auth_token)或通过环境变量注入(配合 systemd drop-in)。 -
输入校验:脚本应过滤
$1(用户名),禁止路径遍历或命令注入(如拒绝含/、..、空格、特殊符号的用户名)。 - 错误处理:curl 失败、超时、HTTP 非 2xx 响应时,脚本应静默退出(不输出任何内容),sshd 将回退到其他认证方式(如密码)或拒绝登录。
- 性能影响:每次登录都会触发一次 API 调用,建议 API 具备缓存能力(如 Redis 缓存 5 分钟),避免成为瓶颈。
-
日志审计:可在脚本中追加简单日志(如
logger -t ssh-keys "fetch for $USERNAME: $(date)"),便于排查。
四、调试与验证方法
不要直接重启后测试登录,先本地模拟验证:
- 切换到
nobody用户运行脚本:sudo -u nobody /usr/local/bin/fetch-pubkey.sh alice,确认能正确输出公钥。 - 检查 sshd 日志:
sudo journalctl -u sshd -f,尝试登录时观察是否出现AuthorizedKeysCommand ... returned status 0或相关错误(如 permission denied、timeout)。 - 临时在脚本开头加入
echo "$(date): $@" >> /tmp/akc.log,确认参数传递和执行时机。

















