Two-factor authentication with MikroTik, xinetd, and gmail

Sometimes setting up a VPN may be overkill for the requirements of remote access, and in that case there are secure alternatives to opening a firewall port to the outside world. My introduction to MikroTik devices came with the requirement that a client have employees accessing their office computers via. remote desktop, and I arrived at using SSH tunneling for the task due to the security offered, along with simplicity of setup on the end user’s computers. Since then, multiple client have adopted these low-cost routers for similar uses.

I still use SSH for my own remote needs (shell access and file transfer, really), and wanted a secure way to tunnel to my home network on a shared/potentially monitored computer, without bringing a private key with me which could be compromised. And, as always, I was in the mood to write some scripts!

The two-factor authentication works like this:

  • The client-side script sends a packet to home, which is caught by xinetd, a service daemon previously elaborated on in this blog.
  • Xinetd calls a script which generates a random username and password.
  • This script creates the user on the MikroTik device, and then sends me a text message with these credentials
  • After 2 minutes, the username/password are removed from the router.

Now, on to the scripts! We have the client side script:

echo x | nc -4u -w1 71.201.###.### 12345
echo -n "Enter 2-factor username: "
ssh -p55533 `read -n 6`@71.201.###.### -L 9922:172.21.31.3:22 

Where 71.201.###.### is my IP address, 12345 is my forwarded port for xinetd, and -L 9922:172.21.31.3:22 is the SSH parameter to open the local port 9922 as a tunnel to the remote 172.21.31.3:22. The next step is to create a NAT rule on the MikroTik router:

/ip firewall nat add action=dst-nat chain=dstnat comment="2-factor auth on ssh" dst-port=12345 
    in-interface=ether1-WAN protocol=udp to-addresses=172.21.31.3

Following this, the xinetd service in /etc/xinetd.d/2fa:

# /etc/xinetd.d/2fa
service 2fa
{
 disable = no
 type = UNLISTED
 socket_type = dgram
 protocol = udp
 wait = yes
 server = /opt/2falogin
 bind = 172.21.31.3
 port = 12345
 user = derek
}

And the script at /opt/2falogin:

#!/bin/bash
NEW_USER=$(cat /dev/urandom | tr -dc 'a-km-zA-HK-Z1-9' | fold -w 6 | head -n 1)
NEW_PASS=$(cat /dev/urandom | tr -dc 'a-km-zA-HK-Z1-9' | fold -w 8 | head -n 1)
echo -e "user: $NEW_USER npass: $NEW_PASSntime: 120 seconds" | mail -s '2-factor auth' '2155551212@tmomail.net'
MTIK="ssh -i /home/derek/.ssh/rb750gl-derek derek@172.21.31.1"
$MTIK user add name=$NEW_USER password=$NEW_PASS group=ssh-only
$MTIK user print
sleep 120
$MTIK user remove 4

Note that a user print command is called to refresh the router’s users so that the following remove command works. The user index 4 is also hard-coded and is specific to my configuration.

ssmtp is used to let the host computer send email via. gmail, and its configuration (and using with text message destinations) is best left to another blog.

To wrap this all up, this system is really intended for a single-user home network. Having this system in place offers a few benefits:

  • “Road warrior” setup, where outside access cannot be restricted based on IP address
  • Time-restricted-use, pseudo-random credentials are generated on demand and sent directly to the end-user, via a secondary channel.