OpenSSH堡垒机PermitOpen无法解析FQDN问题求助
问题分析与解决方案
问题根源
OpenSSH authorized_keys 中配置的 permitopen=FQDN:port,是在SSH连接建立的瞬间完成DNS解析的,解析后的IP会被作为允许访问的目标存储。后续通过SOCKS隧道发送的请求,sshd只会检查目标IP是否匹配之前解析的结果,不会重新对客户端发送的FQDN做DNS查询,也不会直接匹配FQDN本身。
这就导致:
- 若连接建立时,FQDN仅能通过
/etc/hosts解析(比如当时DNS服务不可用),后续只有该hosts映射的IP会被允许; - 即便后续FQDN的DNS解析结果变化,sshd也不会触发新的DNS查询,直接判定请求不匹配规则导致失败。
解决方案
1. 改用IP:port配置(最稳定)
如果内部资源IP固定,直接在authorized_keys中写permitopen=IP:port,彻底规避DNS解析问题,这也是最可靠的方式。
2. 用command结合脚本实现动态FQDN访问控制
若必须使用FQDN(比如IP频繁变化),可以放弃permitopen,改用command限制用户仅能运行SOCKS代理,并通过脚本动态检查目标FQDN:
- 修改
authorized_keys,添加command限制:command="/usr/local/bin/ssh_socks_acl.sh",no-agent-forwarding,no-X11-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... - 编写访问控制脚本
/usr/local/bin/ssh_socks_acl.sh:#!/bin/bash # 定义允许访问的FQDN:port列表 ALLOWED_TARGETS=( "internal-app.example.com:80" "db.example.com:5432" ) # 解析SOCKS连接请求的目标 if [[ "$SSH_ORIGINAL_COMMAND" =~ ^connect ([^ ]+) ([0-9]+)$ ]]; then TARGET_FQDN="${BASH_REMATCH[1]}" TARGET_PORT="${BASH_REMATCH[2]}" TARGET="$TARGET_FQDN:$TARGET_PORT" # 检查目标是否在允许列表中 for ALLOWED in "${ALLOWED_TARGETS[@]}"; do if [[ "$TARGET" == "$ALLOWED" ]]; then # 执行连接(此时会动态解析FQDN) exec nc "$TARGET_FQDN" "$TARGET_PORT" fi done # 拒绝未授权访问 echo "Access denied to $TARGET" >&2 exit 1 else # 仅允许SOCKS代理请求 echo "Invalid command" >&2 exit 1 fi - 给脚本添加执行权限:
chmod +x /usr/local/bin/ssh_socks_acl.sh
该方案通过脚本接管SOCKS连接的目标校验,动态解析FQDN,绕过OpenSSH本身的permitopen解析限制。
3. 调整sshd启动时的DNS环境(仅适配固定FQDN场景)
若FQDN地址不经常变化,可确保sshd启动时DNS服务已正常运行,或临时调整nsswitch.conf的hosts顺序优先DNS,但这无法解决动态解析问题,仅能保证连接建立时的解析正确性。
验证步骤
- 重新建立SSH隧道:
ssh -D 1080 user@bastion-host - 测试SOCKS5h请求:
curl --socks5h localhost:1080 https://internal-app.example.com - 堡垒机上抓DNS请求:
tcpdump -i any udp port 53,此时能看到脚本触发的DNS查询
内容的提问来源于stack exchange,提问作者AlexSun.dr
相关产品推荐
相关产品推荐

