Blog·Tanky WooABOUTTAGSRSS

最近完善一个审计功能,在 SSH 登录时需要获取登录用户的公私钥或其指纹。调研后发现 AuthorizedKeysCommand 可以满足需求。

AuthorizedKeysCommand 指定脚本查找用户的公钥文件做认证,在登录认证层面调用,可接受的参数有用户尝试登录时使用的私钥对应公钥,指纹、登录用户等变量;输出要求是 0 或多行 authorized_keys 格式的输出,sshd 服务会将用户登录使用的私钥和脚本输出的公钥列表校验,只要其中一个公钥满足匹配,则认证通过;通过相关配置 AuthorizedKeysCommandUser 指定脚本的执行用户。

默认此配置项未设置,从 AuthorizedKeysFile 定义的公钥列表文件中寻找用户公钥,也就是默认的 .ssh/authorized_keys .ssh/authorized_keys2

一个简单的样例,只是打印传进来的这些变量,直接输出公钥列表文件内容,实际认证依然使用公钥文件:

# /etc/ssh/sshd_config
AuthorizedKeysCommand /opt/ssh_auth.sh  %u %k %t %f %h
AuthorizedKeysCommandUser root
AuthorizedKeysFile      none
# /opt/ssh_auth.sh
username=$1
pubkey=$2
keytype=$3
fingerprint=$4
home=$5
echo "$username\n$pubkey\n$keytype\n$fingerprint\n$home" >> /tmp/ssh_auth.log

cat ${home}/.ssh/authorized_keys ${home}/.ssh/authorized_keys2

这个配置项有一个常见的使用场景:用户的公钥列表不存在服务器本地,而是存在统一的 CMDB 中,这样当有人入职或离职需要增删公钥列表时,不需要全部服务器更新公钥文件,只需要更新 CMDB 数据即可,解决了本地公钥文件带来的更新成本、更新滞后且容易遗漏等问题。但是需要注意的是如果只依赖 AuthorizedKeysCommand 脚本,可能存在和 CMDB 之间网络不通导致的无法登录服务器的情况。

还有一个需要注意的地方,OpenSSH 对 AuthorizedKeysCommandAuthorizedKeysFile 处理的逻辑顺序在新旧版本中调整了。

在 8.x 之前的版本,优先使用 AuthorizedKeysCommand 进行认证,如果认证失败,继续使用 AuthorizedKeysFile 认证:

If a key supplied by AuthorizedKeysCommand does not successfully authenticate and authorize the user then public key authentication continues using the usual AuthorizedKeysFile files.

在 8.x 及之后版本,优先使用 AuthorizedKeysFile,如果未找到匹配的才继续使用 AuthorizedKeysCommand 认证:

AuthorizedKeysCommand is tried after the usual AuthorizedKeysFile files and will not be executed if a matching key is found there.

本地测试时版本是 8.1_p1,此时代码的逻辑顺序已经调整了,但是文档未更新,导致测试时发现一直未调用脚本进行认证,所以上面配置样例中强制设置 AuthorizedKeysFile noneCHANGELOG / BUG