You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenSSH:实现不存在的用户登录并向pam_exec传递真实密码

OpenSSH:实现不存在的用户登录并向pam_exec传递真实密码

我之前碰到过一模一样的场景,折腾了好一阵子才弄明白问题出在哪——当本地没有这个用户时,OpenSSH会默认跳过真实密码的传递流程,直接给PAM模块发一个无效的认证请求,导致你的pam_exec根本拿不到用户输入的真密码。下面是我亲测有效的解决步骤:

1. 调整OpenSSH配置,允许不存在的用户进入PAM流程

首先得让sshd别提前把不存在的用户挡在门外,而是把认证权交给PAM处理。编辑/etc/ssh/sshd_config,确保以下配置项正确:

UsePAM yes
PasswordAuthentication yes
# 关闭键盘交互认证,避免干扰密码传递流程
KbdInteractiveAuthentication no
# 允许所有用户尝试登录(不要限制特定用户)
AllowUsers *
# 可选:给新创建的用户指定默认shell,比如bash
# DefaultShell /bin/bash

修改完后重启sshd服务生效:

systemctl restart sshd

2. 修改PAM配置,让pam_exec优先获取真实密码

核心问题出在PAM的执行顺序上——默认情况下,PAM会先调用pam_unix.so检查本地用户,一旦用户不存在,这个模块直接返回失败,后面的pam_exec连拿到真实密码的机会都没有。我们要把pam_exec放在最前面,并且用关键参数确保它能拿到真实密码。

编辑PAM的sshd配置文件/etc/pam.d/sshd,调整认证模块的顺序:

# 先运行自定义的认证脚本,expose_authtok是关键!让脚本从标准输入读真实密码
# success=1表示脚本认证成功的话,跳过下1个模块(也就是后面的pam_unix)
# default=ignore表示脚本失败时,忽略结果继续执行后面的模块
auth    [success=1 default=ignore]  pam_exec.so expose_authtok /path/to/your/auth_script.sh
# 再调用系统默认的远程登录认证模块(包含pam_unix)
auth    include      system-remote-login

这里的expose_authtok是重中之重,它强制pam_exec从标准输入读取用户输入的真实密码,而不是用OpenSSH生成的假密码。

3. 编写你的认证脚本,处理验证和用户创建

接下来写pam_exec调用的脚本,它要完成三件事:拿真实密码、调用webservice验证、验证通过则创建本地用户。

示例脚本/path/to/your/auth_script.sh:

#!/bin/bash

# 从PAM环境变量获取用户名
USER="$PAM_USER"
# 读取真实密码(因为用了expose_authtok,密码会从标准输入传入)
read -r PASSWORD

# 可选:添加日志方便排查,日志文件要确保pam_exec有权限写入
echo "$(date '+%Y-%m-%d %H:%M:%S'): 尝试认证用户 $USER" >> /var/log/pam_auth.log

# 调用你的外部webservice验证用户名和密码,这里用curl举例,根据实际情况调整
AUTH_RESPONSE=$(curl -s -X POST \
  -d "username=$USER&password=$PASSWORD" \
  https://your-webservice-domain/auth-endpoint)

# 假设webservice返回"ok"表示验证通过
if [ "$AUTH_RESPONSE" = "ok" ]; then
    # 检查本地用户是否存在
    if ! id -u "$USER" >/dev/null 2>&1; then
        # 创建用户,-m表示自动创建home目录,-s指定默认shell
        useradd -m -s /bin/bash "$USER"
        echo "$(date '+%Y-%m-%d %H:%M:%S'): 为用户 $USER 创建本地账号" >> /var/log/pam_auth.log
    fi
    # 返回0告诉PAM认证成功
    exit 0
else
    echo "$(date '+%Y-%m-%d %H:%M:%S'): 用户 $USER 认证失败,webservice返回: $AUTH_RESPONSE" >> /var/log/pam_auth.log
    # 返回非0表示认证失败
    exit 1
fi

给脚本添加执行权限:

chmod +x /path/to/your/auth_script.sh

注意事项

  • pam_exec是以root身份运行的,所以useradd这类命令不需要sudo,直接执行就行
  • 要确保脚本里的curl(或其他调用webservice的工具)能正常访问目标服务,注意防火墙、代理、SSL证书等问题
  • 日志文件要提前创建并设置好权限,比如touch /var/log/pam_auth.log && chmod 600 /var/log/pam_auth.log,避免脚本写入失败
  • 如果webservice有超时设置,最好给curl加上--timeout参数,避免PAM流程卡住

这样设置之后,当不存在的用户尝试SSH登录时,sshd会把请求交给PAM,pam_exec先拿到真实密码去webservice验证,验证通过后自动创建本地用户,最后完成登录流程。

备注:内容来源于stack exchange,提问作者Joel Guzmán

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 13:27:27