ARTICLE / 2021.03.07

OpenVPN for IoT : Linux Server, Various Clients including RaspiZero

Using a AWS Linux server, and Raspberry Pi Zero clients Situation Lots of linux devices (and embedded devices) behind firewalls without public IP address Publicly accessible computer (AWS) Goals Connect from the server (or office PC) to these devices Somethin…

Using a AWS Linux server, and Raspberry Pi Zero clients

Situation

  • Lots of linux devices (and embedded devices) behind firewalls without public IP address
  • Publicly accessible computer (AWS)

Goals

  • Connect from the server (or office PC) to these devices
  • Something easier than ssh port forwarding
  • Ability to connect a publicly accessible site (e.g. MyIoT.com/device1) to the device1 network (private) on arbitrary port. This will allow viewing of devices from the internet.
  • Secure, robust and expandable

Solution

  • OpenVPN (this post)
  • Other options are SSH tunnels, IPSec, propriety VPN, etc

Details

Setup OpenVPN Server and CA

  • Setup OpenVPN CA, clients and server with excellent linux tutorial.
  • Use nc to test UDP ports and firewall
  • Modifed some scripts to facilitate key creation

add_client.sh

Run on the openvpa server to create a new client

#!/bin/bash

#
# Create a OpenVPN client configuration, wait for CA signing, then configure the client machine with it
#
# Requires "client" to be ssh accessible to setup client machine
#

# First argument: Client identifier
if [ $# -ne 1 ] then
        echo Wrong args - supply name like "client3"
        exit 1
fi

EASY_RSA_DIR=~/easyrsa3/
KEY_DIR=~/client-configs/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf

# make keys
cd "$EASY_RSA_DIR"
./easyrsa --batch --req-cn="$1" gen-req "$1" nopass

# copy req to CA
read -p "Run 'make_client $1' on the CA machine,copy back '$1.crt' and then press enter"

# put everything in KEY_DIR
cp pki/private/$1.key ~/client-configs/keys/

# package up
cat ${BASE_CONFIG} \
    <(echo -e '<ca>') \
    ${KEY_DIR}/ca.crt \
    <(echo -e '</ca>\n<cert>') \
    ${KEY_DIR}/${1}.crt \
    <(echo -e '</cert>\n<key>') \
    ${KEY_DIR}/${1}.key \
    <(echo -e '</key>\n<tls-auth>') \
    ${KEY_DIR}/ta.key \
    <(echo -e '</tls-auth>') \
    | sudo tee ${OUTPUT_DIR}/${1}.ovpn 1>/dev/null

# copy client openvpn config to client. It includes everything required for the client.
scp $OUTPUT_DIR/$1.ovpn $1:.

# install openvpn on client and start
scp install_openvpn_client.sh $1.ovpn
ssh $1

install_openvpn_client.sh

Run on the client machine to start openvpn


#!/bin/sh
# run on the client 
# First argument: Client identifier

if [ $# -ne 1 ]
 then
        echo Wrong args - supply name of .ovpn file like "client1.ovpn"
        exit 1
fi

sudo apt install openvpn openvpn-systemd-resolved
sudo cp $1 /etc/openvpn/client.ovpn
sudo systemctl enable openvpn@client
sudo systemctl start openvpn@client

make_client_cert.sh

Run on the CA machine to sign the certificate request

#!/bin/bash
 # First argument: Client identifier
if [ $# -ne 1 ]; then
        echo Wrong args - supply name like "client3"
        exit 1
fi

SERVER=live.openvpnserver-changeme.com
KEY_DIR=$SERVER:client-configs/keys
REQ_DIR=$SERVER:easyrsa3/pki/reqs

EASY_RSA_DIR=~/easyrsa3/

cd "$EASY_RSA_DIR"

# get .req from openvpn server
scp $REQ_DIR/$1.req /tmp

# process request
./easyrsa --batch import-req /tmp/$1.req $1
./easyrsa --batch sign-req client $1

# put client cert to openvpn server
scp pki/issued/$1.crt $KEY_DIR/

Setup of Raspi Client

Coming soon. Spoiler: write a long script to do a million little things to get a key.