SSHD动态管控端口转发:如何获取客户端-L参数并实现基于权限的访问限制
嘿,这个需求太贴合大规模运维的痛点了——静态配置PermitOpen根本扛不住上万用户和数万主机的规模,必须搞动态验证才行。我来给你捋捋可行的方案,尤其是能精准拿到客户端-L参数并做权限校验的方法。
首先得纠正一个误区:你之前尝试的PAM auth阶段拿不到端口转发参数,因为SSH的端口转发请求是用户认证完成之后才会发送给sshd的,auth阶段还没到那一步呢,所以得换思路。
最优雅的方案:用OpenSSH的PermitOpen exec:动态验证(推荐)
从OpenSSH 7.8版本开始,官方支持了PermitOpen exec:的特性——每次客户端发起端口转发请求(不管是-L本地转发还是其他类型),sshd都会调用你指定的脚本,把目标主机和端口作为参数传进去,脚本返回0就允许转发,非0就直接拒绝。这完全契合你的动态权限校验需求,而且不需要维护任何静态列表!
具体操作步骤:
修改sshd_config配置
在你的跳板机sshd配置文件里添加这两行:AllowTcpForwarding yes PermitOpen exec:/usr/local/bin/check_permitopen.sh注意:如果之前有
PermitOpen的其他配置,要替换掉,因为这个参数是排他的。编写权限校验脚本
创建/usr/local/bin/check_permitopen.sh脚本,内容如下:#!/bin/bash # 脚本会自动接收sshd传递的两个参数:目标主机、目标端口 TARGET_HOST="$1" TARGET_PORT="$2" # 获取当前登录的用户名(sshd会以登录用户身份执行这个脚本) CURRENT_USER="$USER" # 调用你的权限校验工具 if /path/to/can_access "$CURRENT_USER" "$TARGET_HOST"; then # 权限通过,允许转发 exit 0 else # 权限不通过,拒绝转发 echo "You are not authorized to access $TARGET_HOST" >&2 exit 1 fi给脚本加上执行权限:
chmod +x /usr/local/bin/check_permitopen.sh测试验证
从你的工作站执行:ssh -NL 1234:my-server:3389 the-jumphost如果
can_access脚本返回允许,转发就能正常建立;如果返回拒绝,sshd会直接断开这个转发请求,用户连不上敏感主机。
兼容旧版本OpenSSH的方案:ForceCommand+进程端口解析
如果你的跳板机OpenSSH版本低于7.8,没法用上面的特性,那就用ForceCommand来拦截所有会话,然后解析当前SSH进程的端口转发信息。
修改sshd_config
添加:ForceCommand /usr/local/bin/validate_forwards.sh这个配置会让所有登录的用户先执行你的校验脚本,再进入shell(如果需要的话)。
编写校验脚本
validate_forwards.sh的核心逻辑是找到当前SSH会话对应的sshd进程,然后解析它的端口转发目标:#!/bin/bash CURRENT_USER="$USER" # 获取当前会话的sshd父进程ID(因为ForceCommand脚本是sshd子进程的子进程) SSHD_PID="$PPID" # 用ss命令找到这个sshd进程关联的所有端口转发 # 输出格式类似:LISTEN 0 128 127.0.0.1:1234 0.0.0.0:* users:(("sshd",pid=1234,fd=6)) FORWARDS=$(ss -tulpn | grep "pid=$SSHD_PID") # 解析每个转发的目标主机 while read -r LINE; do # 提取目标地址(比如从"-> my-server:3389"里拿到my-server) # 这里的解析逻辑可能需要根据ss命令的输出格式调整 TARGET=$(echo "$LINE" | grep -oP '-> \K[^:]+') if [ -n "$TARGET" ]; then if ! /path/to/can_access "$CURRENT_USER" "$TARGET"; then echo "Unauthorized access to $TARGET" >&2 exit 1 fi fi done <<< "$FORWARDS" # 校验通过,放行到shell exec "$SHELL"同样给脚本加执行权限,然后测试即可。
注意事项
- 如果你不需要用户登录跳板机的shell,只允许端口转发,可以在sshd_config里加上
PermitTTY no,这样用户连上来只能做转发,没法打开终端。 - 对于反向转发(-R),如果需要限制,同样可以用
PermitOpen exec:的方案,只要调整脚本的校验逻辑就行。 - 确保
can_access脚本的权限正确,只能被root或者特定用户执行,避免被篡改。
备注:内容来源于stack exchange,提问作者John Oxley

