如何在docker环境中设置sslh的透明模式?

如何在docker环境中设置sslh的透明模式?

我想在端口 443 上设置 sslh,以转发到位于两个 docker 容器中的 https 和 openvpn。由于我想在长期内提供基于 IP 的 https ACL,因此我希望 sslh 向 Web 服务器提供真正的客户端 IP(又称为 sslh 的“透明”模式)。

据我了解文档这个答案例如,sslh会在内网中伪造外部请求,并需要反馈服务器的答案来转换端口,以便与客户端进行通信。

我的问题是 iptables 设置。有两种可能的位置可以运行 sslh:在主机上或在 docker 网络内的容器中。

我设法使文档中描述的“默认”设置发挥作用,即:主机上的 sslh 可以透明地转发到主机上的服务。

但是,我无法在主机或容器中使用透明 sslh 来与容器化服务器配合使用。更具体地说,我标记应路由到 sslh 的流量的 iptables 规则从未匹配任何数据包。

例如对于 https 网络服务器我会:

iptables -t mangle -A OUTPUT -p tcp --sport 443 --source 172.25.0.2 --jump SSLH

使用这张图表我试图辨别容器的虚拟以太网设备、docker 桥接器、docker NAT 和 iptables 如何协同工作,但我无法理解。

为了更好地讨论这个问题,我们假设以下几点:

  • 主机(eth0):1.1.1.1
  • docker-bridge(br0):172.25.0.0/16
    • webserver(veth1):172.25.0.2:443(如有必要,在主机上公开为 8443)
    • openvpn(veth2):172.25.0.3:1194(如有必要,转发到主机)
    • 容器中的 sslh(与主机 sslh 互斥):172.25.0.4:443(转发到主机)
  • 主机上的 sslh(与容器 sslh 互斥):端口 443
  • 客户端:8.8.8.8

这是我的失败模型,当浏览器连接到主机:443 并且 sslh 处于透明模式时应该发生的情况

  • sslh 冒充原始客户端 8.8.8.8 连接到 172.25.0.2:8443
  • Web 服务器通过 veth1 应答与 8.8.8.8 的 TCP 握手
  • 数据包进入 br0
  • 路由决定通过 ent0 发送
  • iptables 的 mangle 输出链将其标记为 sslh 的流量(这对我来说不起作用)
  • 该标记表示将数据包路由到本地 lo 设备
  • sslh 接收它,转换端口并将其发送回客户端

上面列出的问题是,我不知道 Web 服务器出站流量的过滤标准:我应该使用 docker 内部端口 443 还是映射端口 8443?docker IP 172.25.0.2 还是其他?归根结底是:mangle 输出规则是在 docker 的 NAT 之前还是之后运行?

我以为我可以将 sslh 放入 docker 网络以避免考虑 NAT,但我仍然无法让 iptables 规则匹配。

我不知道该怎么办。

答案1

我知道这个帖子有点“老旧”,但我刚遇到过同样的情况,一开始我真的迷路了。但我设法让它工作了。不过这可能不是最优雅的解决方案(请随意发表建议!)

我的设置与您的非常相似:

  • 主机(1.1.1.1)
    • 安全套接字层:443
    • SSH:2222
    • 码头工人
      • 容器1(容器:443 -> 主机:4443)
      • 容器2(容器:443 -> 主机:1194)

使用 sslh 的文档,我成功地将透明模式用于 ssh:443。因此,显然,在透明模式下路由到主机进程是可行的。

这是我当前的一套(主机)规则

iptables -t mangle -N SSLH
iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j SSLH
#The next line routes ssh@host via sslh back to the client. Add more rules like this for other services running on the host (with their respective port)
iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 2222 -j SSLH
iptables -t mangle -A SSLH -j MARK --set-mark 0x1 
iptables -t mangle -A SSLH -j ACCEPT
ip rule add fwmark 0x1 lookup 100 
ip route add local 0.0.0.0/0 dev lo table 100

此路由通过 ssh 在主机(端口 2222)和客户端之间透明地路由 ssh 流量。但是,为 docker 容器添加类似的规则对我来说不起作用(可能是由于 docker 自身广泛的 iptables 规则/网络)

我的解决方案现在是这样的:为 docker 容器分配一个固定的(容器内部)ip,并让 sslh 通过这个 ip 和该容器的内部端口访问容器,而不是通过 1.1.1.1:4443 或 1.1.1.1:1194

  • 容器1:10.1.0.100
  • 容器2:10.2.0.100

我的 /etc/default/sslh 文件现在有此条目

DAEMON_OPTS="-n --user sslh --transparent --timeout 5 --listen 0.0.0.0:443 --ssh 1.1.1.1:2222 --ssl 10.1.0.100:443 --openvpn 10.2.0.100:443 --pidfile /var/run/sslh/sslh.pid"

为了给容器分配一个固定的 IP,您只需创建一个新的网络,例如通过 cli 或通过 docker-compose。

由于我使用的是docker-compose,所以我这样做了:

version: '2.4'
services:
  nginx:
    image: nginx
    ports:
      - "80:80"
      - "4443:443"
    networks:
      static-network:
          ipv4_address: 10.1.0.100
      default: null

  static-network:
    ipam:
      config:
        - subnet: 10.1.0.0/16

该解决方案将把容器“nginx”添加到两个网络:首先是具有固定 IP 10.1.0.100 的新“静态网络”,以及默认网络(如果您想通过自动生成的默认网络链接同一个 docker-compose 文件中的两个容器,则很方便)。

不过,我必须承认,这个解决方案只是一种权宜之计。我根本无法深入了解路由和 iptables 的魔力,我只能编写更好的路由规则。然而,这个权宜之计对我来说已经完成了工作:透明的 sslh 代理到主机和 docker 容器。

答案2

谢谢@systemofapwne!

在读了你对这篇文章的回答后,我终于设法使一些工作正常进行。

但是,我必须做一些额外的步骤。为了更好地理解,我还绘制了网络设置的小图:

网络草案

为了允许从主机网络(在主机上运行的 SSLH)进行访问,我通过 docker_gwbridge 添加了一条主机路由,以便能够到达容器(bridge/overlay)的内部 docker 网络:

ip route add $(docker network inspect proxy --format "{{(index .IPAM.Config 0).Subnet}}") via $(docker network inspect docker_gwbridge --format "{{(index .IPAM.Config 0).Gateway}}")

注意:将“proxy”替换为您需要从主机访问的 docker 网络的名称。

对于 SSLH 配置:

# /etc/conf.d/sslh
# ssh: 192.168.10.250 as it's the only listening IP in the sshd config, and on port 50022 
# tls: traefik container ip address in its standalone bridge/overlay network
DAEMON_OPTS="-t 2 -p 192.168.10.250:443 --ssh 192.168.10.250:50022 --tls 172.16.100.2:443 --user sslh --transparent"

对于 SSH 流量,我的规则是相同的。正如您所写,您不能处理 SSL 流量,只能处理 SSH 流量:

iptables -t mangle -N SSLH
iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j SSLH
#The next line routes ssh@host via sslh back to the client. Add more rules like this for other services running on the host (with their respective port)
iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 50022 -j SSLH
iptables -t mangle -A SSLH -j MARK --set-mark 0x1 
iptables -t mangle -A SSLH -j ACCEPT
ip rule add fwmark 0x1 lookup 100 
ip route add local 0.0.0.0/0 dev lo table 100

我在 SSLH 的 github 上发布了更多有关设置的详细信息:https://github.com/yrutschle/sslh/issues/411

相关内容