This docker image proxies specific tcp ports across a Fortinet VPN to remote host using openfortivpn and socat. SOCKS5 proxy is also available in container and served by glider on port 8443 by default.
This work is based on following projects:
- openfortivpn-haproxy - added changes enabling easy 2FA authentication
- docker-forticlient - generic workflow
- docker-fortivpn-socks5 - glider build
- docker-forticlient-with-proxy - setup masquerade
This work is focused on 2FA (Two-Factor) authentication and expect a text file to be written with 2FA token prior to VPN process start.
Generic workflow:
- VPN is not starting with container
- 'inotifywait' is looking for any writes (close_write,moved_to,create) in specific folder
- when new 2FA token is available in '2fa.txt' file, any existent VPN instance is terminated and new one connected using provided username+password+token
- there is no automatic restart for VPN service
-
Clone this repository
git clone https://github.com/gooorooox/docker-forti-proxy-2fa
-
Build the image
docker build ./docker-forti-proxy-2fa -t "gooorooo/docker-forti-proxy-2fa:latest"
You can get most recent docker image from Docker Hub:
docker pull gooorooo/docker-forti-proxy-2fa
VPN_ADDR
: IP address and a port of the server, separated by colonVPN_USER
: usernameVPN_PASS
: passwordVPN_2FA_DIR
: folder for logs and 2FA token fileVPN_2FA_FILE
: full path to 2FA token fileENABLE_IPTABLES_LEGACY
: set to any value to force iptables-legacy (not needed for Alpine)ENABLE_PORT_FORWARDING
: set to any value to enable ports forwardingSOCKS_PROXY_PORT
: glider port to listen
To configure forwarded ports, use environment variables with names that start
with PORT_FORWARD
and contain a special string (outlined below). More than
one port can be forwarded by using a unique variable name (PORT_FORWARD1
,
PORT_FORWARD2
, etc). The variable should contain a string that is formatted
like one of the following:
REMOTE_HOST
:REMOTE_PORT
LOCAL_PORT
:REMOTE_HOST
:REMOTE_PORT
PROTOCOL
:LOCAL_PORT
:REMOTE_HOST
:REMOTE_PORT
REMOTE_HOST
is a public hostname or ip address (note that a current limitations prevents the hostname from being resolved within the VPN)
REMOTE_PORT
an integer between 1-65535
LOCAL_PORT
an integer between 1-65535. If omitted, port 1111 is used.
PROTOCOL
either tcp or udp. If omitted, tcp is used.
Once docker container is deployed and started, SOCKS5 proxy will be running on port 8443.
At this point VPN is not started yet, you need to enter a token to '/tmp/2fa/2fa.txt' file. Once token is provided, you can check your VPN connection with following command:
curl -x http://<HOST-IP>:8443 --insecure -I https://<VPN-ONLY-IP>
Log files of VPN and Proxy are available under VPN_2FA_DIR
\logs folder.
Current DSM (7.2.1-69057 Update 3) might require to enable "Execute control using high privilege" capability in order to allow /dev/ppp device management.
version: "2.3"
services:
vpn:
image: gooorooo/docker-forti-proxy-2fa:latest
container_name: forti_proxy_2fa
network_mode: bridge
devices:
- /dev/net/tun:/dev/net/tun
- /dev/ppp:/dev/ppp
volumes:
- <HOST-SHARED-FOLDER>:/tmp/2fa
cap_add:
- NET_ADMIN
environment:
- VPN_ADDR=1.1.1.1:443
- VPN_USER=myusername
- VPN_PASS=mysecretpassword
- VPN_2FA_DIR=/tmp/2fa/
- VPN_2FA_FILE=/tmp/2fa/2fa.txt
- SOCKS_PROXY_PORT=8443
ports:
- 8443:8443/tcp
expose:
- 8443
restart: "unless-stopped"
@echo off
title FortiVPN 2FA
set PSPING=<path_to_exe>\psping64.exe
set VPN_IP=10.10.10.10
set VPN_PORT=10111
set COUNT=0
:check_loop
set /a COUNT=%COUNT%+1
echo Trying for %VPN_IP%:%VPN_PORT% (attempt #%COUNT%)
:: pause for 1 second
ping 127.0.0.1 -n 1 > nul
%PSPING% /accepteula -4 -n 1 -w 0 -q %VPN_IP%:%VPN_PORT% 2>nul | find "Lost = 1" >nul && goto check_loop || echo goto connect_vpn
:connect_vpn
set FILE_PATH=x:\<shared_folder>\vpn\2fa.txt
cls
echo VPN connection port is listening.
set /P sec_token="Enter token (6 digits):"
echo %sec_token% > %FILE_PATH%
echo OK