我有以下设置:
- 运行 docker 服务的 CentOS 主机
- 用户定义的 docker 桥接网络
- 2 个 Docker 容器连接到用户定义的桥接网络
- OpenVPN 安装(当前在主机上运行。也可以在 docker 容器中运行)
- 一些连接到 OpenVPN 的客户端
如何允许 docker bridge 网络上的 docker 容器与 tun0 网络上的 openvpn 客户端进行通信?
我希望能够以透明的方式在 docker1(10.10.0.3)和连接到 vpn(172.19.0.x 范围)的客户端之间进行基于 tcp 的通信。
我需要在 docker(网络/iptables/...)端和主机(iptables?)上设置什么?
答案1
语境
我一直在使用 Kyle Manna 提供的非常好的 Docker 容器(https://github.com/kylemanna/docker-openvpn)我正在使用所谓的“偏执”文档来设置我的 OpenVPN 服务器,但在我看来,这应该是标准方式,而不是偏执的方式。
配置
为了允许选定的 Docker 容器和 VPN 客户端之间建立双向连接,您需要创建一个 Docker 网络,在该网络上附加容器,并允许 VPN 客户端访问该容器。VPN 服务器将是这些容器之一。
VPN 服务器应该具有client-to-client
、topology subnet
、dev tun0
(或其他 tun 设备)和push "route <docker net IP> <docker net mask>"
配置。
VPN 服务器的主机应配置为支持将 IP 数据包从一个子网转发到另一个子网。这意味着将 sysctl ip_forward 设置为 1(如果安装了 Docker,则应该如此),允许来自 tun 设备的数据包通过 iptables FORWARD 链并设置正确的路由。这可以用以下命令来总结:
$ sudo sysctl -w net.ipv4.ip_forward=1
$ sudo iptables -A FORWARD -i tun+ -j ACCEPT
$ sudo ip route add 192.168.255.0/24 via <IP address of OpenVPN server container>
无论如何,以下是我用来设置服务器的选项:
$ docker run --rm --net=none -it -v $PWD/files/openvpn:/etc/openvpn kylemanna/openvpn:2.4 ovpn_genconfig -u udp://<FQDN> -N -d -c -p "route <docker net IP> <docker net range>" -e "topology subnet"
这应该生成类似于以下内容的服务器配置文件:
server 192.168.255.0 255.255.255.0
verb 3
key /etc/openvpn/pki/private/vpn.example.com.key
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/vpn.example.com.crt
dh /etc/openvpn/pki/dh.pem
tls-auth /etc/openvpn/pki/ta.key
key-direction 0
keepalive 10 60
persist-key
persist-tun
proto udp
# Rely on Docker to do port mapping, internally always 1194
port 1194
dev tun0
status /tmp/openvpn-status.log
user nobody
group nogroup
client-to-client
### Push Configurations Below
push "dhcp-option DNS 8.8.8.8"
push "route 172.20.20.0 255.255.255.0"
### Extra Configurations Below
topology subnet
具体例子
现在我将举一个具体的例子。在这个例子中,我将在主机 vpn.example.com 上的 Docker 中运行上面提到的 OpenVPN 服务器。此容器连接到 Docker 网络 docker-net-vpn。以下是命令(在这个例子中,我直接在服务器上生成服务器配置,并跳过 CA 生成,请按照上面提到的项目的偏执文档进行操作):
$ docker network create --attachable=true --driver=bridge --subnet=172.20.20.0/24 --gateway=172.20.20.1 docker-net-vpn
$ docker run --rm --net=none -it -v $PWD/files/openvpn:/etc/openvpn kylemanna/openvpn:2.4 ovpn_genconfig -u udp://vpn.example.com -N -d -c -p "route 172.20.20.0 255.255.255.0" -e "topology subnet"
$ docker run --detach --name openvpn -v $PWD/files/openvpn:/etc/openvpn --net=docker-net-vpn --ip=172.20.20.2 -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn:2.4
$ sudo sysctl -w net.ipv4.ip_forward=1
$ sudo iptables -A FORWARD -i tun+ -j ACCEPT
$ sudo ip route add 192.168.255.0/24 via 172.20.20.2
第一个命令创建一个专用的新 Docker 网络,并定义一个新的子网。我们将把 OpenVPN 服务器连接到此网络。
第二个命令使用与第一个命令中定义的相同子网创建 OpenVPN 配置。
第三个命令创建 OpenVPN 服务器。它连接到新创建的 Docker 网络并使用固定 IP。
第四和第五个命令配置IP转发。
最后一条命令通过 OpenVPN 容器固定 IP 向 VPN 客户端配置添加了一条新路由。
笔记
我还没有尝试过,但应该可以限制 iptables 的 FORWARD 规则。Docker 网络创建创建了一个新的桥接设备。此桥接设备的br-<ID>
ID 是 Docker 网络 ID 的前 12 个字符。可以使用 获取此 ID docker network inspect -f '{{.Id}}' docker-net-vpn | cut -b-12
。因此,以下命令可能更具限制性(因此安全性更好),但仍应允许我们的流量被路由:
$ NET_VPN_BRIDGE="br-$(docker network inspect -f '{{.Id}}' docker-net-vpn | cut -b-12)"
$ sudo iptables -A FORWARD -i tun+ -o ${NET_VPN_BRIDGE} -j ACCEPT