■dockerのhwdsl2/ipsec-vpn-serverでIPsecVPNを試してみる。
$ docker search ipsec -f stars=3
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
hwdsl2/ipsec-vpn-server VPN server with IPsec/L2TP, Cisco IPsec and … 360 [OK]
cpuguy83/ipsec 6 [OK]
jpillora/ipsec-vpn-server A simple, multi-user IPsec/L2TP and Cisco IP… 4 [OK]
ibotty/ipsec-libreswan minimal priviliged ipsec container for use i… 3 [OK]
■hwdsl2にはインストールするタイプもある。
https://github.com/hwdsl2/setup-ipsec-vpn
■公式のドキュメントを参照する。
https://hub.docker.com/r/hwdsl2/ipsec-vpn-server
■dockerイメージのダウンロード
$ docker pull hwdsl2/ipsec-vpn-server
■PSK共有キー、ユーザ名、パスワードを決める。
$ echo 'VPN_IPSEC_PSK=your_ipsec_pre_shared_key
VPN_USER=your_vpn_username
VPN_PASSWORD=your_vpn_password' > vpn.env
■例えば。
$ sed -i 's/your_ipsec_pre_shared_key/myshare/' vpn.env
$ sed -i 's/your_vpn_username/labunix/' vpn.env
$ sed -i 's/your_vpn_password/xxxxx/' vpn.env
$ cat vpn.env
VPN_IPSEC_PSK=myshare
VPN_USER=labunix
VPN_PASSWORD=xxxxx
■起動してみる。
$ docker run \
--name ipsec-vpn-server \
--env-file ./vpn.env \
--restart=always \
-v ikev2-vpn-data:/etc/ipsec.d \
-p 500:500/udp \
-p 4500:4500/udp \
-d --privileged \
hwdsl2/ipsec-vpn-server
■ログの確認
$ docker logs ipsec-vpn-server | sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.70/X.X.X.X/g'
Trying to auto discover IP of this server...
Setting up IKEv2, please wait...
================================================
IPsec VPN server is now ready for use!
Connect to your new VPN with these details:
xl2tpd[1]: Not looking for kernel SAref support.
Server IP: X.X.X.X
IPsec PSK: myshare
Username: labunix
Password: xxxxx
Write these down. You'll need them to connect!
Important notes: https://git.io/vpnnotes2
Setup VPN clients: https://git.io/vpnclients
------------------------------------------------
IKEv2 setup successful. Details for IKEv2 mode:
VPN server address: X.X.X.X
VPN client name: vpnclient
Client configuration is available at:
/etc/ipsec.d/vpnclient.p12 (for Windows)
/etc/ipsec.d/vpnclient.sswan (for Android)
/etc/ipsec.d/vpnclient.mobileconfig (for iOS & macOS)
*IMPORTANT* Password for client config files:
z5oZ8sgr7coK58pR
Write this down, you'll need it for import!
To start using IKEv2, see: https://git.io/ikev2docker
================================================
Redirecting to: /etc/init.d/ipsec start
Starting pluto IKE daemon for IPsec: .
xl2tpd[1]: Using l2tp kernel support.
xl2tpd[1]: xl2tpd version xl2tpd-1.3.12 started on bfb92615642d PID:1
xl2tpd[1]: Written by Mark Spencer, Copyright (C) 1998, Adtran, Inc.
xl2tpd[1]: Forked by Scott Balmos and David Stipp, (C) 2001
xl2tpd[1]: Inherited by Jeff McAdams, (C) 2002
xl2tpd[1]: Forked again by Xelerance (www.xelerance.com) (C) 2006-2016
xl2tpd[1]: Listening on IP address 0.0.0.0, port 1701
■ネットワークの確認。
この環境ではbridgeに接続されている。
$ ip a | lsec -sep "^[0-9]" 172.17 | grep "^[0-9]\|inet "
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
1bc3de918d9d bridge bridge local
b181ffc1729c host host local
3511d6025db8 none null local
$ docker network inspect $(docker network ls | awk '$2 ~ /bri/{print $1}') | jq -r '.[].Containers' | grep "Name\|IPv4Address"
"Name": "ipsec-vpn-server",
"IPv4Address": "172.17.0.2/16",
■以下の構成なので、X.X.X.XからのNAT(500/udp,4500/udp)を開ける。
X.X.X.XはWANでもDMZでも基本構成は同じなので、まずはDMZで構成してみる。
$ echo "[VPN-Client Z.Z.Z.Z] -- [X.X.X.X gw Y.Y.Y.252] -- [Y.Y.Y.92 host 172.17.0.1] -- [ipsec-vpn-server 172.17.0.2]"
[VPN-Client Z.Z.Z.Z] -- [X.X.X.X gw Y.Y.Y.252] -- [Y.Y.Y.92 host 172.17.0.1] -- [ipsec-vpn-server 172.17.0.2]
■dockerホストに接続すれば、ipsec-vpn-serverにポート転送される。
$ sudo iptables -L -n 2>/dev/null| lsec -sep '^$' 172.17
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT udp -- 0.0.0.0/0 172.17.0.2 udp dpt:4500
ACCEPT udp -- 0.0.0.0/0 172.17.0.2 udp dpt:500
■まずはdockerホストのポート転送を無視して、ipsec-vpn-serverまでルーティングしてみる。
■Fortigateのルーティング、NAT設定の例
config router static
edit 3
set dst 172.17.0.0 255.255.0.0
set gateway Y.Y.Y.92
set device "lan"
next
end
config firewall service custom
edit "VPN"
set category "Tunneling"
set udp-portrange 500 4500
next
end
config firewall vip
edit "DMZ-VPN"
set uuid cdf4c53c-75f1-51eb-1080-afd0cbf057d1
set extip X.X.X.X
set extintf "dmz"
set mappedip "172.17.0.2"
next
end
config firewall policy
edit 18
set name "DMZ-VPN"
set uuid XXXXX
set srcintf "dmz"
set dstintf "lan"
set srcaddr "WLAN-Router"
set dstaddr "DMZ-VPN"
set action accept
set schedule "always"
set service "VPN"
set nat enable
next
end
■Androidからの接続ログをipsec-vpn-serverから確認してみる。
※Android側からの設定は以下を参照。
Configure IPsec/L2TP VPN Clients
https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md
$ docker exec -it ipsec-vpn-server ipsec status | \
sed -e 's/^000 //g' | tail -n 12 | \
sed -e 's/[,:;] /&\n /g' | sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.252/Y.Y.Y.252/g'
Total IPsec connections:
loaded 4,
active 1
State Information:
DDoS cookies not required,
Accepting new IKE connections
IKE SAs:
total(1),
half-open(0),
open(0),
authenticated(1),
anonymous(0)
IPsec SAs:
total(1),
authenticated(1),
anonymous(0)
"l2tp-psk"[4] Y.Y.Y.252:64916 STATE_MAIN_R3 (IKE SA established);
EVENT_SA_EXPIRE in 28559s;
newest ISAKMP;
lastdpd=27s(seq in:12602 out:0);
idle;
"l2tp-psk"[4] Y.Y.Y.252:64916 STATE_QUICK_R2 (IPsec SA established);
EVENT_SA_EXPIRE in 28561s;
newest IPSEC;
eroute owner;
isakmp
idle;
"l2tp-psk"[4] Y.Y.Y.252 esp.ed47405@Y.Y.Y.252 esp.16d48007@172.17.0.2 Traffic:
ESPin=3KB ESPout=847B! ESPmax=4194303B
Bare Shunt list:
■ipsec-vpn-serverのトラフィックログ
$ docker exec -it ipsec-vpn-server ipsec whack --trafficstatus | sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.252/Y.Y.Y.252/g'
006
■Androidからイントラ内のWebサーバに接続してみる。
$ echo "[VPN-Client Z.Z.Z.Z] -- [X.X.X.X gw Y.Y.Y.252] -- [Y.Y.Y.92 host 172.17.0.1] \
-- [ipsec-vpn-server 172.17.0.2],[Y.Y.Y.100 Web-server]" | \
graph-easy --dot | dot -T svg -o vpn.png
$ sudo awk '/[0-9]*\/[0-9]*\.[0-9]*\.92/{gsub(" \042","\n&",$0);print $0}' /var/log/apache2/access.log
Y.Y.Y.92 - - [24/Feb/2021:01:56:42 +0900]
"GET / HTTP/1.1" 401 815
"android-app://com.google.android.googlequicksearchbox/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - basic-auth [24/Feb/2021:01:56:54 +0900]
"GET / HTTP/1.1" 200 5378
"android-app://com.google.android.googlequicksearchbox/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - basic-auth [24/Feb/2021:01:56:55 +0900]
"GET /web.css HTTP/1.1" 200 849
"http://Y.Y.Y.100/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - basic-auth [24/Feb/2021:01:56:55 +0900]
"GET /labunix.png HTTP/1.1" 200 5928
"http://Y.Y.Y.100/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - - [24/Feb/2021:01:57:46 +0900]
"-" 408 0
"-"
"-"
■WAN側のポリシーを作成、DDNSの名前でVPN接続してみる。
※接続元のIPはfromJPでGeoIPの国内からのみに制限している。
config firewall vip
edit "WAN-VPN_500"
set uuid XXXXX
set extintf "wan"
set portforward enable
set mappedip "172.17.0.2"
set protocol udp
set extport 500
set mappedport 500
next
end
config firewall vip
edit "WAN-VPN_4500"
set uuid XXXXX
set extintf "wan"
set portforward enable
set mappedip "172.17.0.2"
set protocol udp
set extport 4500
set mappedport 4500
next
end
config firewall policy
edit 19
set name "WAN-VPN"
set uuid XXXXX
set srcintf "wan"
set dstintf "lan"
set srcaddr "fromJP"
set dstaddr "WAN-VPN_4500" "WAN-VPN_500"
set action accept
set schedule "always"
set service "VPN"
set nat enable
next
end
■GWが同じなので、statusはDMZからの接続と違いは無い。
$ docker exec -it ipsec-vpn-server ipsec status | \
sed -e 's/^000 //g' | tail -n 12 | \
sed -e 's/[,:;] /&\n /g' | sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.252/Y.Y.Y.252/g'
Total IPsec connections:
loaded 4,
active 1
State Information:
DDoS cookies not required,
Accepting new IKE connections
IKE SAs:
total(1),
half-open(0),
open(0),
authenticated(1),
anonymous(0)
IPsec SAs:
total(1),
authenticated(1),
anonymous(0)
"l2tp-psk"[6] Y.Y.Y.252:53976 STATE_MAIN_R3 (IKE SA established);
EVENT_SA_EXPIRE in 28763s;
newest ISAKMP;
lastdpd=5s(seq in:12182 out:0);
idle;
"l2tp-psk"[6] Y.Y.Y.252:53976 STATE_QUICK_R2 (IPsec SA established);
EVENT_SA_EXPIRE in 28764s;
newest IPSEC;
eroute owner;
isakmp
idle;
"l2tp-psk"[6] Y.Y.Y.252 esp.684272a@Y.Y.Y.252 esp.69c4b187@172.17.0.2 Traffic:
ESPin=45KB ESPout=608B! ESPmax=4194303B
Bare Shunt list:
■trafficstatusのZ.Z.Z.ZはAndroidのキャリアのグローバルIPになる。
$ docker exec -it ipsec-vpn-server ipsec whack --trafficstatus | sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.252/Y.Y.Y.252/g'
006
■WebサーバのログもDMZからのアクセスと違いはない。
$ sudo awk '/[0-9]*\.[0-9]*\.[0-9]*\.92/&& !/2021:01:56/ \
{if($3 ~ /[A-Za-z0-9]/) \
{gsub(".*","basic-auth",$3);gsub(" \042","\n&",$0);print $0} \
else{gsub(" \042","\n&",$0);print $0}}' /var/log/apache2/access.log | \
sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.100/Y.Y.Y.100/g' -e 's/[0-9]*\.[0-9]*\.[0-9]*\.92/Y.Y.Y.92/g'
Y.Y.Y.92 - - [24/Feb/2021:01:57:46 +0900]
"-" 408 0
"-"
"-"
Y.Y.Y.92 - - [24/Feb/2021:02:42:50 +0900]
"GET / HTTP/1.1" 401 815
"android-app://com.google.android.googlequicksearchbox/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - basic-auth [24/Feb/2021:02:43:01 +0900]
"GET / HTTP/1.1" 200 5378
"android-app://com.google.android.googlequicksearchbox/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - basic-auth [24/Feb/2021:02:43:02 +0900]
"GET /labunix.png HTTP/1.1" 200 5928
"http://Y.Y.Y.100/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
Y.Y.Y.92 - - [24/Feb/2021:02:43:52 +0900]
"-" 408 0
"-"
"-"
■ipsec-vpn-serverのIPは変わる可能性があるので、
dockerホストのポート転送を使用するように設定変更を行う。
■まずはDMZ
set mappedip "172.17.0.2"
edit DMZ-VPN
set mappedip "Y.Y.Y.92"
end
set mappedip "Y.Y.Y.92"
$ docker exec -it ipsec-vpn-server ipsec whack --trafficstatus | \
sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.252/Y.Y.Y.252/g' -e 's/[0-9]*\.[0-9]*\.[0-9]*\.223/Z.Z.Z.223/g'
006
$ sudo awk '/[0-9]*\.[0-9]*\.[0-9]*\.92/&& !/2021:01:56|2021:02:4[23]/ \
{if($3 ~ /[A-Za-z0-9]/){gsub(".*","basic-auth",$3);gsub(" \042","\n&",$0);print $0} \
else{gsub(" \042","\n&",$0);print $0}}' /var/log/apache2/access.log | \
sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.100/Y.Y.Y.100/g' -e 's/[0-9]*\.[0-9]*\.[0-9]*\.92/Y.Y.Y.92/g' | \
lsec -sep ^[A-Z0-9] "/ HTTP/1.1. 200 "
Y.Y.Y.92 - basic-auth [25/Feb/2021:00:17:07 +0900]
"GET / HTTP/1.1" 200 5378
"android-app://com.google.android.googlequicksearchbox/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
■そしてWAN
set mappedip "172.17.0.2"
set mappedip "172.17.0.2"
edit WAN-VPN_500
set mappedip "Y.Y.Y.92"
next
edit WAN-VPN_4500
set mappedip "Y.Y.Y.92"
end
$ docker exec -it ipsec-vpn-server ipsec whack --trafficstatus | \
sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.252/Y.Y.Y.252/g' -e 's/[0-9]*\.[0-9]*\.[0-9]*\.198/Z.Z.Z.198/g'
006
$ sudo awk '/[0-9]*\.[0-9]*\.[0-9]*\.92/&& !/2021:01:56|2021:02:4[23]|2021:00:17/ \
{if($3 ~ /[A-Za-z0-9]/){gsub(".*","basic-auth",$3);gsub(" \042","\n&",$0);print $0} \
else{gsub(" \042","\n&",$0);print $0}}' /var/log/apache2/access.log | \
sed -e 's/[0-9]*\.[0-9]*\.[0-9]*\.100/Y.Y.Y.100/g' -e 's/[0-9]*\.[0-9]*\.[0-9]*\.92/Y.Y.Y.92/g' | \
lsec -sep ^[A-Z0-9] "/ HTTP/1.1. 200 "
Y.Y.Y.92 - basic-auth [25/Feb/2021:00:28:39 +0900]
"GET / HTTP/1.1" 200 5377
"android-app://com.google.android.googlequicksearchbox/"
"Mozilla/5.0 (Linux; Android 8.0.0; ASUS_X00PD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36"
■ルーティングは不要になったので削除。
※DMZ-router側のルーティングも削除
set dst 172.17.0.0 255.255.0.0
delete 3
end
■PSK共有キー、ユーザ名、パスワードの変更のために、
ipsec-vpn-serverを終了する。
また、併せてDMZ-VPN用とWAN-VPN用でセッションを分けるために、
以下を参考に別々のユーザ、パスワードを設定する。
VPN_ADDL_USERS=additional_username_1 additional_username_2
VPN_ADDL_PASSWORDS=additional_password_1 additional_password_2
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bfb92615642d hwdsl2/ipsec-vpn-server "/opt/src/run.sh" 24 hours ago Up 24 hours 0.0.0.0:500->500/udp, 0.0.0.0:4500->4500/udp ipsec-vpn-server
$ docker stop ipsec-vpn-server
ipsec-vpn-server
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker rm $(docker ps -a | awk '/ipsec-vpn-server/{print $1}')
bfb92615642d
$ awk -F'[ =]' '{gsub(".*","XXX",$2);print $1"="$2}' vpn.env
VPN_IPSEC_PSK=XXX
VPN_USER=XXX
VPN_PASSWORD=XXX
VPN_ADDL_USERS=XXX
VPN_ADDL_PASSWORDS=XXX
■イメージ差し替え等のメンテナンスのために、dockerコマンドをスクリプト化しておく。
$ cat hwdsl2
docker run \
--name ipsec-vpn-server \
--env-file ./vpn.env \
--restart=always \
-v ikev2-vpn-data:/etc/ipsec.d \
-p 500:500/udp \
-p 4500:4500/udp \
-d --privileged \
hwdsl2/ipsec-vpn-server
$ chmod +x hwdsl2
$ ./hwdsl2
■差し替え方法
$ docker stop ipsec-vpn-server
$ docker rm $(docker ps -a | awk '/ipsec-vpn-server/{print $1}')
$ docker rmi $(docker image ls | awk '/ipsec-vpn-server/{print $3}')
$ docker pull hwdsl2/ipsec-vpn-server
$ test vpn.env && ./hwdsl2
■普段は以下のように停止、起動、確認をする。
$ docker stop ipsec-vpn-server
$ docker start $(docker ps -a | awk '/ipsec-vpn-server/{print $1}')
$ docker inspect $(docker ps -a | awk '/ipsec-vpn-server/{print $1}') | jq -r '.[].State.Status'
running
$ sudo iptables -L -n 2>/dev/null| lsec -sep '^$' :[4]500
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT udp -- 0.0.0.0/0 172.17.0.2 udp dpt:4500
ACCEPT udp -- 0.0.0.0/0 172.17.0.2 udp dpt:500
$ docker exec -it ipsec-vpn-server ipsec status
$ docker exec -it ipsec-vpn-server ipsec whack --trafficstatus