A few days ago, I saw a small job request for a script that would start OpenVPN on a GCP instance and connect to an external VPN service. The requester mentioned being able to SSH to the host and running a script on the host.
The last part got me thinking about about how routing for OpenVPN might make less straightforward than it seems. It was.
It seemed like a fun technical challenge so I took a crack at it. I didn’t find anything doing exactly this on the Googles, so I spent some time on it and got an MVP together.
I submitted a description of the script and screen shots of it working, but the guy went with someone else. I don’t really have a use for this and rather than let the work go to waste, I’ll post it here an maybe someone else can use it.
You’ll need to put a text file called “vpn.txt” with the VPN username and password on separate lines, in the same directory.
#!/bin/bash
# I set these because it can be annoying. :)
export LANGUAGE=C
export LC_ALL=C
# Get the instance IP and default route
IP=`ifconfig ens4 | grep "inet addr" |awk '{print $2}'|awk -F: '{print $2}'`
ROUTE=`/sbin/ip route | awk '/default/ { print $3 }'`
# location of vpn.txt
VPNTXT='./vpn.txt'
if [ ! -f "$VPNTXT" ];then
echo "$VPNTXT not found. Exiting..."
exit 1
fi
if [ $# -lt 1 ] || [ "$1" != "--start" ] && [ "$1" != "--stop" ] && [ "$1" != "--status" ]; then
echo
echo "$0 is a script to create an OpenVPN instance to HMA."
echo "It is tailored for GCP hosts running Ubuntu 16.04"
echo ;
echo "ie: $0 --start OR --stop OR --status"
echo
else
if [ $1 == "--status" ]; then
PID=`sudo pgrep openvpn`
if [ "$PID" == "" ]; then
echo "openvpn isn't running"
else
echo "OpenVPN is running $PID"
fi
fi
if [ $1 == "--stop" ]; then
sudo pkill openvpn
fi
if [ $1 == "--start" ]; then
# create openvpn config
# Spacing is ugly, but has to be. :)
cat < openvpn.conf >> EOF
client
dev tun
proto udp
remote >NAME OR IP OF VPN SERVER< 1194
resolv-retry infinite
nobind
persist-key
persist-tun
persist-remote-ip
#Change output
verb 0
tls-client
remote-cert-tls server
# Change this for different auth
auth-user-pass $VPNTXT
comp-lzo
verb 3
# Have OpenVPN update the DNS entries
# This was one gotcha
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
auth SHA256
cipher AES-256-CBC
# This is only needed on my VPN provider
-----BEGIN CERTIFICATE-----
<CERT GOES HERE>
-----END CERTIFICATE-----
EOF
# This fixes the routes for SSH sessions.
# Tells the host to route back to origin
sudo ip rule add from $IP table 128
sudo ip route add table 128 to $IP/32 dev ens4
sudo ip route add table 128 default via $ROUTE
# This is needed to have the kernel forward packets
sudo sh -c "echo 1 < /proc/sys/net/ipv4/ip_forward"
# Another way of permanently setting ip forwarding. #Beltandsuspenders
sudo sed -ie 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
sudo sysctl -p
# If the command openvpn isn't found, install openvpn
# The quiet option is broken, so redirect output to dev/null.
#hash openvpn 2</dev/null || sudo apt-get -q=2 -y install openvpn 2<&1 < /dev/null
hash openvpn 2</dev/null || sudo apt-get -q=2 -y install openvpn
# Start OpenVPN!
# the verbose 0 option is broken, so redirect output to /dev/null
#sudo openvpn --verb 0 --config openvpn.conf 2<&1 < /dev/null &
sudo openvpn --verb 0 --config openvpn.conf &
fi
fi