OpenVPN Client with 2FA

fabricapo

New Around Here
Hello, I am trying to configure my ASUS RT-AC66U B1 with 386.5_2 to have an OpenVPN client with 2FA.

Since I need a console to input the 2FA challenge, I connected via ssh and tried to figure out what 'service start_vpnclientX' does. I managed to preserve the files that are created in /etc/openvpn/vpnclientX and I tried launching:

/etc/openvpn/vpnclient2 --cd /etc/openvpn/client2 --config config.ovpn

Everything seems to work (2FA challenge is accepted and the connection to the OpenVPN Server is confirmed) but I am missing one step, which is the routing of all packets.

So I went back and checked one OpenVPN Client configuration that works (no 2FA) and I compared what happens between launching it with service start_vpnclient2 and the direct command.

If I check the log of the service command, I see an additional line, that I do not have when I launch it directly:
openvpn-routing: Routing all traffic through ovpnc2

I am guessing I am missing one command that does the routing. I bet it has to do with iptables, but I can't figure it out (even looking at the source of openvpn.c...).

If anyone has a suggestion, I would much appreciate it.

fabrizio
 

eibgrad

Part of the Furniture
The router uses ip rules to control which OpenVPN client routing table is used for which clients, either ALL, or those defined via the VPN Director. In the case of all, it would be something like the following.

Code:
ip rule add from all table ovpnc2

You can see the results of the additional rule by dumping the RPDB.

Code:
ip rule show

Note, I've over simplied things a bit here. I did NOT consider priority (another argument to the ip rule add command). The router prioritizes its rules, highest to lowest, moving from OpenVPN client #1 thru #5. Higher priority rules are listed above lower priority rules. And the dual WAN's priority rules always take precedence over the OpenVPN rules too.

I'm only mentioning this because I want you to be aware that rule ordering matters. At least if you want the router to work as expected. That's why it's a bit risky to work outside the service command, which would take such details into consideration.
 

Wallace

Occasional Visitor
This is my setup for a site-to-site vpn with openvpn client with 2FA.

Install opkg packages:
opkg install expect tmux bind-tools

Files required:
  1. /jffs/openvpn/client.ovpn
  2. /jffs/openvpn/client-credentials.txt
  3. /jffs/openvpn/start-openvpn-client.sh
  4. /jffs/openvpn/firewall-up.sh
start-openvpn-client.sh starts the OpenVPN client with $OTP is an input parameter.
This startup script uses expect (#!/opt/bin/expect) to automatically insert the 2FA-OTP string at the prompt "CHALLENGE: Enter Authenticator Code" after openvpn command.

start-openvpn-client.sh
Rich (BB code):
#!/opt/bin/expect

set OTP [lindex $argv 0]
eval spawn /usr/sbin/openvpn --config /jffs/openvpn/client.ovpn --auth-user-pass /jffs/openvpn/client-credentials.txt
set prompt "CHALLENGE: Enter Authenticator Code"
interact -o -nobuffer -re $prompt return
send "$OTP\r"
interact

Run this command to start openvpn client with 2FA (OTP):
/jffs/openvpn/start-vpn.sh $OTP <-- your 2FA OTP string

client.ovpn configures the challenge prompt for the 2FA-OTP string.
The prompt should match the prompt in start-openvpn-client.sh
Rich (BB code):
auth-user-pass
static-challenge "Enter Authenticator Code" 1

A new network interface (tun0) is created when the openvpn connection is established.
Rich (BB code):
spawn /usr/sbin/openvpn --config /jffs/openvpn/client.ovpn --auth-user-pass /jffs/openvpn/client-credentials.txt
2022-07-10 11:00:28 OpenVPN 2.5.3 arm-buildroot-linux-gnueabi [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] built on Aug  6 2021
2022-07-10 11:00:28 library versions: OpenSSL 1.1.1k  25 Mar 2021, LZO 2.08
CHALLENGE: Enter Authenticator Code826154
...
2022-07-09 16:21:47 TUN/TAP device tun0 opened
2022-07-09 16:21:47 /usr/sbin/ip link set dev tun0 up mtu 1500
2022-07-09 16:21:47 /usr/sbin/ip link set dev tun0 up
2022-07-09 16:21:47 /usr/sbin/ip addr add dev tun0 172.16.0.1/22
2022-07-10 11:00:34 /usr/sbin/ip route add 172.16.0.1/20 metric 101 via 172.16.232.1

To allow (site-to-site) network traffic routes between local and remote networks over the new network interface (tun0) created by openvpn client.
  1. Configure FORWARD chain to allow forwarding to tun0 interface
  2. Configure network address translation (NAT) to masquerade the source IP of packets sent to tun0 to router's IP
firewall-up.sh
Rich (BB code):
iptables -I OVPN -o tun0 -j ACCEPT
iptables -t nat -I POSTROUTING 1 -o tun0 -j MASQUERADE

Note:
  • These 2 iptables rules allow local network to initiate connections to servers in the remote network.
  • Remote network will not be able to initiate connections to servers in the local network.
 
Last edited:

eibgrad

Part of the Furniture
This is my setup for a site-to-site vpn with openvpn client with 2FA.

Install opkg packages:
opkg install expect tmux bind-tools

Files required:
  1. /jffs/openvpn/client.ovpn
  2. /jffs/openvpn/client-credentials.txt
  3. /jffs/openvpn/start-openvpn-client.sh
  4. /jffs/openvpn/firewall-up.sh
start-openvpn-client.sh starts the OpenVPN client with $OTP is an input parameter.
This startup script uses expect (#!/opt/bin/expect) to automatically insert the 2FA-OTP string at the prompt "CHALLENGE: Enter Authenticator Code" after openvpn command.

start-openvpn-client.sh
Rich (BB code):
#!/opt/bin/expect

set OTP [lindex $argv 0]
eval spawn /usr/sbin/openvpn --config /jffs/openvpn/client.ovpn --auth-user-pass /jffs/openvpn/client-credentials.txt
set prompt "CHALLENGE: Enter Authenticator Code"
interact -o -nobuffer -re $prompt return
send "$OTP\r"
interact

Run this command to start openvpn client with 2FA (OTP):
/jffs/openvpn/start-vpn.sh $OTP <-- your 2FA OTP string

client.ovpn configures the challenge prompt for the 2FA-OTP string.
The prompt should match the prompt in start-openvpn-client.sh
Rich (BB code):
auth-user-pass
static-challenge "Enter Authenticator Code" 1

A new network interface (tun0) is created when the openvpn connection is established.
Rich (BB code):
spawn /usr/sbin/openvpn --config /jffs/openvpn/client.ovpn --auth-user-pass /jffs/openvpn/client-credentials.txt
2022-07-10 11:00:28 OpenVPN 2.5.3 arm-buildroot-linux-gnueabi [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] [AEAD] built on Aug  6 2021
2022-07-10 11:00:28 library versions: OpenSSL 1.1.1k  25 Mar 2021, LZO 2.08
CHALLENGE: Enter Authenticator Code826154
...
2022-07-09 16:21:47 TUN/TAP device tun0 opened
2022-07-09 16:21:47 /usr/sbin/ip link set dev tun0 up mtu 1500
2022-07-09 16:21:47 /usr/sbin/ip link set dev tun0 up
2022-07-09 16:21:47 /usr/sbin/ip addr add dev tun0 172.16.0.1/22
2022-07-10 11:00:34 /usr/sbin/ip route add 172.16.0.1/20 metric 101 via 172.16.232.1

A word of caution.

I do NOT generally recommend using the firmware's user-defined chains for your own purposes. In this case, the OVPN chain. That can change. And in the case of 386.7, it just did!

The OVPN chain that used to be shared between the INPUT and FORWARD chains w/ 386.5_2 and below, is now two (2) separate chains in 386.7; OVPNCI in the INPUT chain, and OVPNCF in the FORWARD chain.

It's just more reliable to insert these kinds of rules at the top of INPUT and/or FORWARD chains than depend on those created and managed by the firmware.

Now as it happens, by default, ALL traffic, regardless of network interface, is allowed *outbound* from the default network (br0). The only exception is traffic explicitly denied w/ the NSFW chain (network services filter), but that only filters access to the WAN anyway, NOT the VPNs. And the replies are handled by the ESTABLISHED rule within the INPUT and FORWARD chains. IOW, afaict, such outbound rules are NOT necessary.

To allow (site-to-site) network traffic routes between local and remote networks over the new network interface (tun0) created by openvpn client.
  1. Configure FORWARD chain to allow forwarding to tun0 interface
  2. Configure network address translation (NAT) to masquerade the source IP of packets sent to tun0 to router's IP
firewall-up.sh
Rich (BB code):
iptables -I OVPN -o tun0 -j ACCEPT
iptables -t nat -I POSTROUTING 1 -o tun0 -j MASQUERADE

Note:
  • These 2 iptables rules allow local network to initiate connections to servers in the remote network.
  • Remote network will not be able to initiate connections to servers in the local network.

The common definition of site-to-site does exactly what your Note section claims otherwise. It *allows* devices on the OpenVPN server side of the tunnel to initiate connections to devices behind the OpenVPN client.

IOW, the first statement is true, but NOT the second. NOT if we are being accurate in the common definition of a site-to-site VPN.

One of the reasons I bring this up is NOT just to be picky, but because it provides an opportunity to point out a security hole you haven't considered. It's still possible for any device on the server side of the tunnel to initiate a connection w/ the router itself on its assigned IP of the tunnel! It *is* site-to-site in that very narrow sense (but we don't typically use that terminology to avoid confusion). That's why the OpenVPN client of the GUI has the Inbound Firewall option, which is set by default to Block such access. And it does that by explicitly adding rules for that purpose.

Code:
iptables -I OVPNCI -i tun11 -j DROP # assumes 386.7 or later
iptables -I OVPNCF -i tun11 -j DROP # assumes 386.7 or later

Granted, when dealing w/ your *own* OpenVPN server, this is probably a lesser concern. But since most ppl are dealing w/ third-party OpenVPN servers (e.g., PIA, NordVPN), such trust can NOT be assumed, hence why that option exists.

Again, I brought it up because you specifically mentioned the fact that remote access was NOT possible from server to client. But it is in that one special case.
 
Last edited:

Wallace

Occasional Visitor
Thanks for the pointers!

Updated firewall file:
  1. /jffs/openvpn/firewall-up.v2.sh
Code:
## Configure NAT to masquerade the source IP of packets sent to tun0 to router's IP
iptables -t nat -I POSTROUTING 1 -o tun0 -j MASQUERADE

## Block inbound from remote site (tun0)
## Drop NEW connections initiated from remote network
iptables -I FORWARD -i tun0 -m state --state NEW -j logdrop
iptables -I INPUT -i tun0 -m state --state NEW -j logdrop

I just started on this "site-to-site" setup on Asuswrt router.
  • To allow all devices in local network to reach all servers/services on remote network hosted on AWS.
  • Without openvpn client on each device on local network.
  • No use case for remote network to connect to devices on local network.
What would be a better description for this type of configuration?

I encountered some challenges while woking on these scripts:
  • Unable to generate 2FA code with oathtool, as oath-toolkit not available on opkg.
  • Using tmux to keep the openvpn client running without a connected ssh session.
  • Unaware on how to configure services to run the connection and firewall scripts.
Ideally, I would like to fully automate OpenVPN client login with 2FA code.
  • Would it be possible to update /Advanced_OpenVPNClient_Content.asp to enter 2FA-key for each OpenVPN client?
  • At OpenVPN client connection time, generate 2FA-OTP with the 2FA-key.
 
Last edited:

eibgrad

Part of the Furniture
I just started on this "site-to-site" setup on Asuswrt router.
  • To allow all devices in local network to reach all servers/services on remote network hosted on AWS.
  • Without openvpn client on each device on local network.
  • No use case for remote network to connect to devices on local network.
What would be a better description for this type of configuration?

I'm not sure there is a common name for it. Most of the time you either describing a NON site-to-site tunnel (or just a tunnel), or else a site-to-site tunnel explicitly.

FWIW, to avoid confusion, I tend to call the former "unidirectional" and the latter "bidirectional". But even that can be misleading (e.g., which direction is unidirectional?).

So I don't have a good answer. As I said, even in the unidirectional configuration, the OpenVPN client itself is still reachable unless you specifically deny access to it from the other side of the tunnel. But I've never seen anyone refer to that as site-to-site. I suppose it falls into that grey area.

I encountered some challenges while woking on these scripts:
  • Unable to generate 2FA code with oathtool, as oath-toolkit not available on opkg.
  • Using tmux to keep the openvpn client running without a connected ssh session.
  • Unaware on how to configure services to run the connection and firewall scripts.
Ideally, I would like to fully automate OpenVPN client login with 2FA code.
  • Would it be possible to update /Advanced_OpenVPNClient_Content.asp to enter 2FA-key for each OpenVPN client?
  • At OpenVPN client connection time, generate 2FA-OTP with the 2FA-key.

I've never even attempted 2FA w/ the OpenVPN clients, nor am I sure what it would take to do so w/ the GUI. That's something you'd have to ask of the developer, @RMerlin.

Once you're working outside the GUI, it can get tricky, esp. if you're not fully aware of all the things the GUI is doing to keep you safe and deal w/ unforeseen issues (keeping the connection alive, providing a killswitch, PBR (policy based routing), etc.). IOW, there's a lot of work involved in making sure you dot all your I's and cross all your T's.
 

Similar threads

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top