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.
(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