Setup IPSec VPN Server with Raspberry Pi

On my previous post, I shared how to configure a direct connection between my private home network and Google Cloud VPN. In my setup I was using my Raspberry Pi as my local VPN Gateway using OpenSwan. In this tutorial I’m going to show how I configure that.

Why did I choose Raspberry Pi?

First is I don’t own/have access to a dedicated VPN device/appliance. Having a Cisco ASA device would have been a good choice just to have that “Enterprise grade” experience but since this is just a POC, I think the Raspberry Pi is very well suited for this. Second, the low power consumption of this pocket-sized computer really makes it a better choice. Instead of running a power-hungry x86 server or DLXXX hardware, I could leave this one up and running all night without worrying about my electricity bill going up. But since we are using OpenSwan, you can definitely run this on any commodity hardware.

On with the installation

I have my pi up and running Raspbian Jessie Lite since I was using it as my Kodi media server. All I need to do now is to install openswan.

root@gateway:~# apt-get install openswan

When prompted ‘Use an X.509 certificate for this host?’, answer ‘No’. If you want to add it, use ‘dpkg-reconfigure openswan’ to come back.

Once installed, let’s configure our ipsec.secrets

root@gateway:~# vi /etc/ipsec.secrets

Add the following to the end of the line. Change raspberrypi_IP with the IP Address of your pi. Change the  pre-shared-key-password with something else. This will be used by both peers for authentication (RFC2409). Generate a long PSK with atleast 30 characters to mitigate brute force attack.

<raspberrypi_IP> %any: PSK "<pre-shared-key-password>"

We now need to define our VPN connection. Edit ipsec.conf

root@gateway:~# vi /etc/ipsec.conf

Add the following connection definition at the bottom part of the config file.

## connection definition in vpc-google ##
conn vpc-google     #vpc-google is the name of the connection
 auto=add
 authby=secret     #since we are using PSK, this is set to secret 
 type=tunnel #OpenSwan support l2tpd as well. For site-to-site use tunnel
 leftsubnet=192.168.0.0/24 # This is our local subnet.
 rightsubnet=10.128.0.0/20 # Remote site subnet.
 leftid=xx.xx.xxx.xx # My public IP
 left=192.168.0.100 # Raspberry PI ip address
 leftsourceip=192.168.0.100 # Raspberry PI ip address
 right=%any
 aggrmode=no

 

Under the default connection, I actually set the following

keyexchange=ike
nat_traversal=yes

I forgot to mention that this Raspberry PI is behind my router. I had to do port forwarding. IPSec uses udp port 500/4500. You need to do port forwarding if your gateway will be behind a router.

Restart openswan service.

root@gateway:~# service ipsec restart

All we need to do now is to configure a VPN Connection in GCP.

Once configured,  we can do the following to check if it’s working as expected.

Check ipsec status

root@gateway:~# service ipsec status
● ipsec.service - LSB: Start Openswan IPsec at boot time
 Loaded: loaded (/etc/init.d/ipsec)
 Active: active (running) since Thu 2017-07-20 14:23:39 UTC; 18s ago
 Process: 6866 ExecStop=/etc/init.d/ipsec stop (code=exited, status=0/SUCCESS)
 Process: 6964 ExecStart=/etc/init.d/ipsec start (code=exited, status=0/SUCCESS)
 CGroup: /system.slice/ipsec.service
 ├─7090 /bin/sh /usr/lib/ipsec/_plutorun --debug --uniqueids yes --force_busy no --nocrsend no --strictcrlpolicy no --nat_traversal yes -...
 ├─7091 logger -s -p daemon.error -t ipsec__plutorun
 ├─7094 /bin/sh /usr/lib/ipsec/_plutorun --debug --uniqueids yes --force_busy no --nocrsend no --strictcrlpolicy no --nat_traversal yes -...
 ├─7095 /bin/sh /usr/lib/ipsec/_plutoload --wait no --post
 ├─7096 /usr/lib/ipsec/pluto --nofork --secretsfile /etc/ipsec.secrets --ipsecdir /etc/ipsec.d --use-auto --uniqueids --nat_traversal --v...
 ├─7100 pluto helper # 0 
 └─7188 _pluto_adns

Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #1: new NAT mapping for #1, was 35.188.205.71:500, now 35.188.205.71:4500
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #1: STATE_MAIN_R3: sent MR3, ISAKMP SA established {auth=OAKLEY_PRESHAR...modp1024}
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #1: the peer proposed: 192.168.0.0/24:0/0 -> 10.128.0.0/20:0/0
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: responding to Quick Mode proposal {msgid:3e4ab184}
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: us: 192.168.0.0/24===192.168.0.100<192.168.0.100>[xx.xxx.xx.xx]
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: them: 35.188.205.71===10.128.0.0/20
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: transition from state STATE_QUICK_R0 to state STATE_QUICK_R1
Jul 20 14:23:44 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: STATE_QUICK_R1: sent QR1, inbound IPsec SA installed, expecting QI2
Jul 20 14:23:45 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: transition from state STATE_QUICK_R1 to state STATE_QUICK_R2
Jul 20 14:23:45 gateway pluto[7096]: "vpc-google"[1] 35.188.205.71 #2: STATE_QUICK_R2: IPsec SA established tunnel mode {ESP/NAT=>0x1baf69...DPD=none}
Hint: Some lines were ellipsized, use -l to show in full.
root@gateway:~#

35.188.205.71 is my GCP VPN Gateway IP. We need to see that IPsec SA established tunnel mode to confirm everything is working fine.

ipsec auto –status

root@gateway:~# ipsec auto --status
000 using kernel interface: netkey
000 interface lo/lo ::1
000 interface lo/lo 127.0.0.1
000 interface lo/lo 127.0.0.1
000 interface eth0/eth0 192.168.0.100
000 interface eth0/eth0 192.168.0.100
000 interface wlan0/wlan0 192.168.1.1
000 interface wlan0/wlan0 192.168.1.1
000 %myid = (none)
000 debug none
000 
000 virtual_private (%priv):
000 - allowed 6 subnets: 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 25.0.0.0/8, fd00::/8, fe80::/10
000 - disallowed 0 subnets: 
000 WARNING: Disallowed subnets in virtual_private= is empty. If you have 
000 private address space in internal use, it should be excluded!
000 
000 algorithm ESP encrypt: id=2, name=ESP_DES, ivlen=8, keysizemin=64, keysizemax=64
000 algorithm ESP encrypt: id=3, name=ESP_3DES, ivlen=8, keysizemin=192, keysizemax=192
000 algorithm ESP encrypt: id=6, name=ESP_CAST, ivlen=8, keysizemin=40, keysizemax=128
000 algorithm ESP encrypt: id=11, name=ESP_NULL, ivlen=0, keysizemin=0, keysizemax=0
000 algorithm ESP encrypt: id=12, name=ESP_AES, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP encrypt: id=13, name=ESP_AES_CTR, ivlen=8, keysizemin=160, keysizemax=288
000 algorithm ESP encrypt: id=14, name=ESP_AES_CCM_A, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP encrypt: id=15, name=ESP_AES_CCM_B, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP encrypt: id=16, name=ESP_AES_CCM_C, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP encrypt: id=18, name=ESP_AES_GCM_A, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP encrypt: id=19, name=ESP_AES_GCM_B, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP encrypt: id=20, name=ESP_AES_GCM_C, ivlen=8, keysizemin=128, keysizemax=256
000 algorithm ESP auth attr: id=1, name=AUTH_ALGORITHM_HMAC_MD5, keysizemin=128, keysizemax=128
000 algorithm ESP auth attr: id=2, name=AUTH_ALGORITHM_HMAC_SHA1, keysizemin=160, keysizemax=160
000 algorithm ESP auth attr: id=5, name=AUTH_ALGORITHM_HMAC_SHA2_256, keysizemin=256, keysizemax=256
000 algorithm ESP auth attr: id=6, name=AUTH_ALGORITHM_HMAC_SHA2_384, keysizemin=384, keysizemax=384
000 algorithm ESP auth attr: id=7, name=AUTH_ALGORITHM_HMAC_SHA2_512, keysizemin=512, keysizemax=512
000 algorithm ESP auth attr: id=9, name=AUTH_ALGORITHM_AES_CBC, keysizemin=128, keysizemax=128
000 algorithm ESP auth attr: id=251, name=AUTH_ALGORITHM_NULL_KAME, keysizemin=0, keysizemax=0
000 
000 algorithm IKE encrypt: id=0, name=(null), blocksize=16, keydeflen=131
000 algorithm IKE encrypt: id=5, name=OAKLEY_3DES_CBC, blocksize=8, keydeflen=192
000 algorithm IKE encrypt: id=7, name=OAKLEY_AES_CBC, blocksize=16, keydeflen=128
000 algorithm IKE hash: id=1, name=OAKLEY_MD5, hashsize=16
000 algorithm IKE hash: id=2, name=OAKLEY_SHA1, hashsize=20
000 algorithm IKE hash: id=4, name=OAKLEY_SHA2_256, hashsize=32
000 algorithm IKE hash: id=6, name=OAKLEY_SHA2_512, hashsize=64
000 algorithm IKE dh group: id=2, name=OAKLEY_GROUP_MODP1024, bits=1024
000 algorithm IKE dh group: id=5, name=OAKLEY_GROUP_MODP1536, bits=1536
000 algorithm IKE dh group: id=14, name=OAKLEY_GROUP_MODP2048, bits=2048
000 algorithm IKE dh group: id=15, name=OAKLEY_GROUP_MODP3072, bits=3072
000 algorithm IKE dh group: id=16, name=OAKLEY_GROUP_MODP4096, bits=4096
000 algorithm IKE dh group: id=17, name=OAKLEY_GROUP_MODP6144, bits=6144
000 algorithm IKE dh group: id=18, name=OAKLEY_GROUP_MODP8192, bits=8192
000 algorithm IKE dh group: id=22, name=OAKLEY_GROUP_DH22, bits=1024
000 algorithm IKE dh group: id=23, name=OAKLEY_GROUP_DH23, bits=2048
000 algorithm IKE dh group: id=24, name=OAKLEY_GROUP_DH24, bits=2048
000 
000 stats db_ops: {curr_cnt, total_cnt, maxsz} :context={0,0,0} trans={0,0,0} attrs={0,0,0} 
000 
000 "vpc-google": 192.168.0.0/24===192.168.0.100<192.168.0.100>[xx.xx.xx.xx]...%any===10.128.0.0/20; unrouted; eroute owner: #0
000 "vpc-google": myip=192.168.0.100; hisip=unset;
000 "vpc-google": ike_life: 3600s; ipsec_life: 1200s; rekey_margin: 180s; rekey_fuzz: 100%; keyingtries: 3 
000 "vpc-google": policy: PSK+ENCRYPT+TUNNEL+PFS+IKEv2ALLOW+SAREFTRACK+lKOD+rKOD; prio: 24,20; interface: eth0; 
000 "vpc-google": newest ISAKMP SA: #0; newest IPsec SA: #0; 
000 "vpc-google": IKE algorithms wanted: AES_CBC(7)_256-SHA1(2)_000-MODP1024(2); flags=-strict
000 "vpc-google": IKE algorithms found: AES_CBC(7)_256-SHA1(2)_160-MODP1024(2)
000 "vpc-google": ESP algorithms wanted: AES(12)_256-SHA1(2)_000; flags=-strict
000 "vpc-google": ESP algorithms loaded: AES(12)_256-SHA1(2)_160
000 "vpc-google"[1]: 192.168.0.0/24===192.168.0.100<192.168.0.100>[xx.xx.xxx.xx]...35.188.205.71===10.128.0.0/20; erouted; eroute owner: #2
000 "vpc-google"[1]: myip=192.168.0.100; hisip=unset;
000 "vpc-google"[1]: ike_life: 3600s; ipsec_life: 1200s; rekey_margin: 180s; rekey_fuzz: 100%; keyingtries: 3 
000 "vpc-google"[1]: policy: PSK+ENCRYPT+TUNNEL+PFS+IKEv2ALLOW+SAREFTRACK+lKOD+rKOD; prio: 24,20; interface: eth0; 
000 "vpc-google"[1]: newest ISAKMP SA: #1; newest IPsec SA: #2; 
000 "vpc-google"[1]: IKE algorithms wanted: AES_CBC(7)_256-SHA1(2)_000-MODP1024(2); flags=-strict
000 "vpc-google"[1]: IKE algorithms found: AES_CBC(7)_256-SHA1(2)_160-MODP1024(2)
000 "vpc-google"[1]: IKE algorithm newest: AES_CBC_128-SHA1-MODP1024
000 "vpc-google"[1]: ESP algorithms wanted: AES(12)_256-SHA1(2)_000; flags=-strict
000 "vpc-google"[1]: ESP algorithms loaded: AES(12)_256-SHA1(2)_160
000 "vpc-google"[1]: ESP algorithm newest: AES_128-HMAC_SHA1; pfsgroup=<Phase1>
000 
000 #2: "vpc-google"[1] 35.188.205.71:4500 STATE_QUICK_R2 (IPsec SA established); EVENT_SA_REPLACE in 671s; newest IPSEC; eroute owner; isakmp#1; idle; import:not set
000 #2: "vpc-google"[1] 35.188.205.71 esp.1baf698c@35.188.205.71 esp.c810f1e5@192.168.0.100 tun.0@35.188.205.71 tun.0@192.168.0.100 ref=0 refhim=4294901761
000 #1: "vpc-google"[1] 35.188.205.71:4500 STATE_MAIN_R3 (sent MR3, ISAKMP SA established); EVENT_SA_REPLACE in 3070s; newest ISAKMP; lastdpd=20s(seq in:0 out:0); idle; import:not set
000 
root@gateway:~#

If tunnel isn’t coming up/establishing, your best pal is tcpdump. Initiate a ping or some traffic from the remote site to your local network. I prefer to start by pinging my local VPN gateway from one of my cloud instance.

root@gateway:~# tcpdump -n "port 4500" -vvvv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:35:24.609126 IP (tos 0x0, ttl 64, id 448, offset 0, flags [DF], proto UDP (17), length 29)
 192.168.0.100.4500 > 35.188.205.71.4500: [bad udp cksum 0xb22a -> 0x2ba3!] isakmp-nat-keep-alive
14:35:24.609953 IP (tos 0x0, ttl 64, id 449, offset 0, flags [DF], proto UDP (17), length 29)
 192.168.0.100.4500 > 35.188.205.71.4500: [bad udp cksum 0xb22a -> 0x2ba3!] isakmp-nat-keep-alive

If everything is ok we can test connectivity from our local network to any of our remote instance.

root@gateway:~# ping 10.128.0.3
PING 10.128.0.3 (10.128.0.3) 56(84) bytes of data.
64 bytes from 10.128.0.3: icmp_seq=1 ttl=64 time=210 ms
64 bytes from 10.128.0.3: icmp_seq=2 ttl=64 time=211 ms
^C
--- 10.128.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 210.571/210.973/211.375/0.402 ms
root@gateway:~# ssh root@10.128.0.3
The authenticity of host '10.128.0.3 (10.128.0.3)' can't be established.
ECDSA key fingerprint is 8f:f7:62:4f:1e:85:ad:1e:50:cc:bc:21:fd:ae:bb:9e.
Are you sure you want to continue connecting (yes/no)? 

From the above, we can see that we are able to connect to one of my instance in GCP.