Docker中安装ipsec-vpn

使用hwdsl2/ipsec-vpn-server创建IPsec-VPN

docker pull hwdsl2/IPsec-vpn-server

创建环境变量文件

cat /opt/src/vpn.env

VPN_PUBLIC_IP=172.12.0.101

VPN_L2TP_NET=192.168.180.0/24

VPN_IPSEC_PSK=123.com

VPN_USER=vpnuser2

VPN_PASSWORD=123.com


启动IPsec VPN Server

docker run \     --name ipsec-vpn-server \     --env-file /opt/src/vpn.env \     --restart=always \     -p 500:500/udp \     -p 4500:4500/udp \     -d --privileged \     hwdsl2/ipsec-vpn-server

采用这种方式启动时,实际上是在内部做了端口的映射:安装docker时,会生成一个bridge虚拟接口docker0, 地址为172.17.0.1, 而启动IPsec-vpn-server时,这个容器默认使用docker0,并在其上虚拟一个接口配置地址为172.17.0.2。 当宿主机收到发往UDP:500报文时,会替换为内部接口的地址172.17.0.2:500(如下所示,可通过iptables –nL看见具体的规则设定)

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(1)

#宿主机docker0网桥接口

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(2)

#宿主机上自动创建的500端口iptables规则

通过netstat可在宿主机上看见端口监听情况:

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(3)

#宿主机的端口监听情况

启动后,可查看docker容器的执行状态(docker ps):

进入容器内部:

docker exec -it ipsec-vpn-server env TERM=xterm bash -l

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(4)

#进入容器内命令行

执行ifconfig可见启动了两个接口,一个eth0(docker0这个桥接口成员之一), 另一个ppp作为L2TP拨号接入端口。在容器内执行netstat –anlp, 可见在eth0端口上监听了udp:500, udp:4500udp:1701(L2TP)

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(5)

#容器内的接口信息

但是在容器外面,我们看不到1701端口的监听,这是因为,一旦写上了IPsec隧道后,所有L2TP报文都会加密并封装成ESP报文,进入容器后才会解封送到容器eth0接口地址的1701的端口上。


win10终端拨入

第一次使用win10终端拨入时,发现无法建立连接,抓包发现IPsec隧道已成功建立,但是无法进入L2TP的认证阶段,查找资料后,发现需要在Win10注册表中添加如下内容并重启

Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PolicyAgent] "AssumeUDPEncapsulationContextOnSendRule"=dword:00000002

重启后,Win10终端终于正确拨入VPN Server


L2TP接口网络问题,导致终端不能上网

拨入后,Win10终端Ping VPN Server端的地址,发现ping 172.17.0.2可通(容器内部),但是ping 172.17.0.1不通(容器外部---宿主机)

检查,发现在Win10拨号建立的PPP端口,地址为192.168.42.10, 与我们环境配置文件所提供的VPN_L2TP_NET=192.168.180.0/24不符合,通过docker ps找到容器对应的CONTAINER ID(如:d5d1c438a8fc) , 然后执行:

docker stop d5d1c438a8fc   #终止容器执行

docker rm d5d1c438a8fc    #删除容器

去掉/opt/src/vpn.env中的VPN_L2TP_NET指定,再次运行容器。进入容器内部执行:

iptables –nL 检查防火墙规则:

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(6)

#容器内的iptables规则


可见规则生效,win10拨入后,能正常访问外网。


查找根本原因是,在容器内的/opt/src/run.sh脚本中,虽然修改了/etc/ipsec.conf , 及防火墙规则修改,但是没有将对应的修改设置到/etc/xl2tpd/xl2tpd.conf, 如下图所示:


在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(7)

#容器内的xl2tpd.conf配置

方法一: 若确实需要修改L2TP_NET, 除了修改vpn.env文件外,还需要修改内部的/etc/xl2tpd/xl2tpd.conf配置文件。

方法二: 修改容器内的防火墙规则:

iptables -t nat -A POSTROUTING -s 192.168.42.0/24 -o eth0 -j MASQUERADE

iptables-save


容器内的虽有修改,需要保存到一个新Image中

docker commit 084bc4bdc5a0 ipsec-vpn-server:version4

下次启动时,使用新的image来启动:

docker run \

    --name ipsec-vpn-server \

    --env-file /opt/src/vpn.env \

    --restart=always \

    -p 500:500/udp \

    -p 4500:4500/udp \

    -d --privileged \

    ipsec-vpn-server:version4


Docker网络子系统支持以下网络驱动:


单机安装时,只能看到三种类型(bridge, host, none)

docker network ls 

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(8)

# docker network ls


主机模式(host)

通过命令--network=host 指定,使用host模式的容器可以直接使用docker host的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(9)

#主机模式

无网络模式(none)

这种网络模式下容器只有lo回环网络,没有其他网卡。none网络可以在容器创建时通过 --network=none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。


桥接模式

容器的默认网络模式,docker在安装时会创建一个名为docker0的Linux bridge,在不指定--network的情况下,创建的容器都会默认挂到docker0上面。

在Docker中安装ipsec-vpn过程记录(在Docker中安装ipsec-vpn过程记录)(10)

#桥模式

创建一个容器之后一个新的网络接口被挂载到了docker0上,这个就是容器创建时创建的虚拟网卡。bridge模式为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,使容器之间,容器和docker host之间实现网络隔离。


主机模式启动ipsec-vpn

上面,我们用的是bridge模式启动的容器,现在修改为通过主机模式启动ipsec-vpn

删除已有容器后,通过如下命令重新创建并执行:

docker run \

    --name ipsec-vpn-server \

    --env-file /opt/src/vpn.env \

    --network=host \

    --restart=always \

    -d --privileged \

hwdsl2/ipsec-vpn-server

此时,进入容器内部,我们通过ifconfig可看到,所有的接口信息与宿主机的接口信息一致。


碰见的问题:

Win10再次拨号l2tp-ipsec-vpn, 发现第一个报文就未响应。检查后发现,宿主机的防火墙接口未放开udp 500, 4500和1701端口

firewall-cmd --get-active-zone

internal

  interfaces: ens4

external

  interfaces: eth0

增加internal区域放开端口1701, 500, 4500

firewall-cmd --add-port=1701/udp --zone=internal –permanent

firewall-cmd --add-port=500/udp --zone=internal –permanent

firewall-cmd --add-port=4500/udp --zone=internal --permanent

firewall-cmd –reload

执行后再次检查端口开放情况:

firewall-cmd --list-ports --zone=internal                    

4500/udp 500/udp 1701/udp

Win10再次连接成功

,