Home

This is an example to demonstrate setting up a VPN connection. A software VPN is built between regions (using openswan). No real data is moved, but ping is used to show connectivity.

This is just an exercise I did while studing for the AWS SysOps Associate certification.

There are a few variables I define for this script, prefaced with a "$". These should be replaced by you the reader before being used in any commands. (I find this more helpful than trying to figure out what IP address needs to be replaced with what other IP address, etc)

As a point of reference, it took me around 4 hours to get everything working the first time I tried this, with much trouble shooting along the way (and in a much different order). I deleted everything and started from scratch the next day; while it went a bit smoother, there were still issues and it took me over an hour to get setup correctly. The third time, I wrote down the bullet outline below almost verbatim and was able to get everything working in around half an hour, while capturing the screenshots you see below. Items I missed from my outline that needed to be added below: the internet gateway needs to be attached to subnet, and a default security group is created with the VPC (no need to create manually).

Preliminaries:

Write down your home ip address. Call it $MY_IP. This is used to allow SSH accces in the security group later.

Pick two different regions. I choose Oregon and Ohio. Oregon will be a vpn-only VPC with no internet gateway. The Ohio VPC will have an internet gateway. It will have two instances, one to provide the software VPN connection, and another to act as a "client" that uses the VPN.


Outline

Ohio

Oregon

(additional software configuration steps on the instances)


In the Ohio region, Create vpc

name: vpc-ohio-vpn-192-168-0-0-s16
CIDR: 192.168.0.0/16

Create subnet

name: sub-ohio-vpn-az-2a-192-168-99-0-s24
CIDR: 192.168.99.0/24

Call this $VPN_OHIO_SUBNET

Create internet gateway and attach to vpc

Launch two EC2 instances, one for the client and one for the VPN provider. Select the VPC just created. Choose the default security group. I use an ubuntu 2017 image (ami-618fab04) because this is a bit easier to get the VPN software setup (I normally choose debian).

Assign elastic ips to the instances. Make a note of the private ip address for the vpn provider. Call it $EC2_OHIO_VPN_PRIVATE_IP. Associate the other elastic ip with the ec2-vpn-client instance.

Disable source/dest check on vpn instance

Modify default route for the VPC (it's created for you). Add route to internet through internet gateway and add route to Oregon subnet through ec2-vpn instance. You'll need to start typing the instance name (ec2-vpn-provider) or id for it to show up in the dropdown; it will change to the id when you select it.

Associate the route with the subnet.

Modify vpc security group to allow ssh from your ip. The default security group is created when you create the VPC.

On to the Oregon region.

Create vpc

name: vpc-oregon-vpn-10-2-0-0-s16
CIDR: 10.2.0.0/16

Create subnet

name: sub-oregon-vpn-az-2a-10-2-4-0-s24
availability zone: us-west-2a
CIDR: 10.2.4.0/24

Call this $VPN_OREGON_SUBNET

Modify existing security group, allow ping from Ohio subnet

Create customer gateway from the VPC in Ohio to Oregon. This is the "customer" side, so it will use the public ip for the vpn-provider (the elastic ip).

name: cgw-oregon-vpn
routing: static
ip address: $EC2_OHIO_VPN_PUBLIC_IP

Create VPG

And attach to subnet

Create a VPN using the customer gateway and virtual private gateway. This step takes some time.

name: vpn-connection-oregon
virtual private gateway: vpg-oregon-vpn
customer gateway (existing): cgw-oregon-vpn
routing options: static
static ip prefixes: $VPN_OHIO_SUBNET

You can see that the VPN isn't connected yet.

Modify the route table. Add a route to the Ohio subnet through the VPG.

Associate the route with the subnet.

Retrieve the VPN info. This is used in the configuration on the instance.

Scroll down til you find a section like the following:

!
! The tunnel group sets the Pre Shared Key used to authenticate the
! tunnel endpoints.
!
tunnel-group 52.38.174.43 type ipsec-l2l
tunnel-group 52.38.174.43 ipsec-attributes
   pre-shared-key uHDAcJVNwlXLOPNvEZJOd3BGR7obVU.U

The ip address is the VPN tunnel IP (call it $TUNNEL_IP). This is the endpoint the VPN software (on ec2-vpn-provider) will connect to. The pre-share-key string (call it $VPN_KEY) is used to allow the connection.

At this point everything is setup on AWS. All that's left is configuring the instances. SSH into the ec2-vpn-provider instance. The following steps need to happen before the VPN will work:

Run the following commands:

sudo apt-get update
sudo apt-get install devscripts rng-tools libgmp3-dev libssl-dev gawk flex bison iproute2 iptables
wget https://download.openswan.org/openswan/openswan-2.6.49.1.tar.gz
tar -xzvf openswan-2.6.49.1.tar.gz
cd openswan-2.6.49.1/
make programs
sudo make programs install

I switched to root for the remainder of the setup.

sudo su -

Edit the openswan config, using your favorite editor.

/etc/ipsec.conf

comment out virtual_private line

#virtual_private=

change protostack to netkey

protostack=netkey

At the bottom, add a new connection. Replace the $variables with the values from above.

conn home-to-aws
   type=tunnel
   authby=secret
   #left=%defaultroute
   left=$EC2_OHIO_VPN_PRIVATE_IP
   leftid=$EC2_OHIO_VPN_PUBLIC_IP
   leftnexthop=%defaultroute
   leftsubnet=$VPN_OHIO_SUBNET
   right=$TUNNEL_IP
   rightsubnet=$VPN_OREGON_SUBNET
   pfs=yes
   auto=start

Done editing the config file. Save and exit. Here's what my config looks like, using the values from this run

Now setup the shared key.

touch /etc/ipsec.secrets
chmod 600 /etc/ipsec.secrets 
echo '$EC2_OHIO_VPN_PUBLIC_IP $TUNNEL_IP : PSK "$VPN_KEY"' >> /etc/ipsec.secrets

Note the double quotes around the pass key (and replace the variables before running/pasting). Also note, root owns the secrets file.

edit /etc/sysctl.conf and add this at the end

net.ipv4.ip_forward=1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

Save and exit. Run sysctl -p to refresh

sysctl -p

At this point, the VPN should be setup.

/etc/init.d/ipsec start

Test it out with a ping to the private instance in Oregon.

Not shown, but at this point if you were to view the VPN status in the AWS console, one of the tunnel status' would now say "UP".

The "client" instance only needs to know how to route traffic to Oregon. Run the following, then ping should work.

sudo route add -net $VPN_OREGON_SUBNET gw $EC2_OHIO_VPN_PRIVATE_IP