Skip to content

Instantly share code, notes, and snippets.

@winhamwr
Created June 4, 2012 22:37
Show Gist options
  • Star 63 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save winhamwr/2871257 to your computer and use it in GitHub Desktop.
Save winhamwr/2871257 to your computer and use it in GitHub Desktop.
Creating a repeatable, dynamic site to site VPN with OpenSwan on Ubuntu 10.04 from Amazon EC2

Creating a dynamic site-to-site VPN with OpenSwan on Ubuntu 10.04 on EC2

Wes Winham winhamwr@gmail.com

There are many tutorials floating around the web that almost get you a dynamic VPN in EC2. The goal of this tutorial is to be a one-stop-shop for this specific setup.

This is heavily derived from this EC2 example and this Ubuntu 10.04 example.

What You'll Get

  • Config files that don't change when new instances are launched (the private ec2 ip doesn't matter).
  • An EC2 box that can securely access a private subnet on the remote network.
  • No special access from the remote endpoint to your EC2 box.
  • The ability to use Elastic IPs to manage which box is connected.
  • Compatibility with cisco and openswan endpoints.
  • No need to update the remote endpoint config.

Things You'll Need

  • A fresh Ubuntu 10.04 instance on EC2
  • $ELASTIC_IP: An elastic IP
  • $CONN_NAME: A unique name for your connection. eg. my_ec2_vpn
  • $RIGHT_PUBLIC_IP: The public IP of your other VPN endpoint.
  • $SECURE_PSK: A random pre-shared key to secure your connection.
  • $RIGHT_SUBNET: The private subnet your EC2 box should access on the remote network:

Note: If you only need to access a single IP on the remote network, use a /32 netmask for your $RIGHT_SUBNET. eg. 192.169.3.54/32

Configuration

First, spin up your EC2 instance and attach your Elastic IP.

Install OpenSwan

SSH into your EC2 instance and run:

$ sudo apt-get install openswan

Fix Linux Networking

Once OpenSwan is installed, you'll have access to the $ sudo ipsec verify command. This command checks certain linux network paramenters to ensure that your system properly supports OpenSwan.

Run this command and you should see something like:

$ sudo ipsec verify
Checking your system to see if IPsec got installed and started correctly:
Version check and ipsec on-path                                 [OK]
Linux Openswan U2.6.23/K2.6.32-318-ec2 (netkey)
Checking for IPsec support in kernel                            [OK]
NETKEY detected, testing for disabled ICMP send_redirects       [FAILED]

  Please disable /proc/sys/net/ipv4/conf/*/send_redirects
  or NETKEY will cause the sending of bogus ICMP redirects!

NETKEY detected, testing for disabled ICMP accept_redirects     [FAILED]

  Please disable /proc/sys/net/ipv4/conf/*/accept_redirects
  or NETKEY will accept bogus ICMP redirects!

Checking for RSA private key (/etc/ipsec.secrets)               [OK]
Checking that pluto is running                                  [OK]
Pluto listening for IKE on udp 500                              [OK]
Pluto listening for NAT-T on udp 4500                           [OK]
Two or more interfaces found, checking IP forwarding            [FAILED]
Checking for 'ip' command                                       [OK]
Checking for 'iptables' command                                 [OK]
Opportunistic Encryption Support                                [DISABLED]

The gist of this is that the Ubuntu AMI's must use the NETKEY stack and that you must make configuration tweaks to support that. You also need to enable IP forwarding because the EC2 instance has multiple network devices.

You will make these changes using the /etc/sysctl.conf file and the sysctl command. This will cause changes in the proc file system at paths like /proc/sys/net/ipv4/conf/*/send_redirects, but by editing this file, you ensure those changes are reflected on reboot.

Edit /etc/sysctl.conf and add or uncomment the following lines:

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.eth0.send_redirects = 0

net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.eth0.accept_redirects = 0

Now use the sysctl command to load your new configuration:

$ sudo sysctl -p /etc/sysctl.conf

If you succeeded, running $ sudo ipsec verify again should show everything [OK] with the exception of Opportunistic Encryption Support, which we don't need.

Open the EC2 Security Group

In order for the VPN to initiate a connection, we must allow the traffic to pass through EC2's firewall. This is managed via Security Groups.

To modify the ec2 security groups, open the AWS Console, select EC2 and then select the Security Groups section.

Open UDP access on ports 500 and 4500 for a group in use by your EC2 instance.

Configure IPSec

You'll configure your IPSec connection using 3 different files:

  • /etc/ipsec.conf: This is the main configuration file, where we declare overall configurations and then define the $RIGHT_SUBNET as a non-private range.
  • /etc/ipsec.d/$CONN_NAME.conf: Included via the include /etcipsec.d/*.conf line in /etc/ipsec.conf, we use this to define our specific tunnel.
  • /etc/ipsec.secrets: Here we define the pre-shared key used by the connection.

You'll control reloading these configuration files with:

$ sudo service ipsec stop
$ sudo service ipsec start

Modify the following files to match this configuration, remembering to replace the $ALL_CAPS variables with the actual value.

Configure: /etc/ipsec.conf

version 2.0

config setup
		nat_traversal=yes
		virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$RIGHT_SUBNET
		protostack=netkey

include /etc/ipsec.d/*.conf

Configure: /etc/ipsec.d/$CONN_NAME.conf

conn $CONN_NAME
		authby=secret
		forceencaps=yes
		auto=start
		left=%defaultroute
		leftid=$ELASTIC_IP
		leftsourceip=$ELASTIC_IP
		right=$RIGHT_PUBLIC_IP
		rightid=$RIGHT_PUBLIC_IP
		rightsubnet=$RIGHT_SUBNET

Configure: /etc/ipsec.secrets

We use 0.0.0.0 for one side of the connection to ensure that no matter the ec2 internal ip we use to identify ourselves (as indicated by left=%defaultroute), we use this key if the connection is coming from our expected remote endpoint.

$RIGHT_PUBLIC_IP 0.0.0.0: PSK "$SECURE_PSK"

Restart OpenSwan

Now let's actually load our spanking-new configuration files.

$ sudo service ipsec stop
$ sudo service ipsec start

Test the Connection

To test the connection, run the following command (replacing $CONN_NAME with the appropriate value):

$ sudo ipsec auto --up $CONN_NAME

If everything is kosher, you should see two lines similar to the following (apd is the value of $CONN_NAME in this case):

117 "apd" #3: STATE_QUICK_I1: initiate
004 "apd" #3: STATE_QUICK_I2: sent QI2, IPsec SA established tunnel mode

Awesome. Now our tunnel is up, so let's see if we can send some traffic through. Pick an IP address in your $RIGHT_SUBNET that should respond to pings and run:

$ ping <something_on_right_subnet>

You should see pings coming back.

Testing Without Ping

If you don't have a box to target that should respond to ping, you can try running a port scan to see if you can at least reach the machine.

$ nmap -PN <something_on_right_subnet>

Monitoring traffic

While you're running your ping or nmap, you can view the traffic with tcpdump.

$ tcpdump -n host <RIGHT_PUBLIC_IP>

If you don't see ESP packets in tcpdump, then they aren't being tunneled. Try:

$ tcpdump -n host <something_on_right_subnet>

If that shows ICMP (or other if using nmap) packets, then you're sending packets around the tunnel.

@kdjomeda
Copy link

I have successfully used this using ubuntu 14.04 just that ipsec verify would fail for Two or more interfaces found, checking IP forwarding because of an old perl script as it seems. My only problem is that I can't route through it even though I have added the route on the machine behind the ubuntu-gateway. Is there any amazon trick.

ubuntu-gateway:
iptables -t nat -A POSTROUTING -s [my-network]/24 -j MASQUERADE

client-ubuntu behind ubuntu-gateway
route add -net [other-network]/24 netmask 255.255.255.0 gw [vpn server ip]

@barboni
Copy link

barboni commented May 27, 2015

@kdjomeda just stumbled upon the same problem. could you please tell how you solved it?

@dcnoren
Copy link

dcnoren commented Aug 13, 2015

@barboni, you need to add static routes in AWS VPC to tell traffic destined for the remote subnet to route via the VPN endpoint within AWS. For instance, if AWS VPC tunnel endpoint is 10.100.10.5, and the remote subnet on other side of VPN is 192.168.1.0/24, then enter a route in VPC routing tables for 192.168.1.0/24 via 10.100.10.5 (or just specify EC2 instance name).

@omnibs
Copy link

omnibs commented May 17, 2016

I was having trouble with this configuration, the tunnel would go up alright but no traffic was ever tunneled.

If I tried telnetting to something in the rightsubnet I'd get:

$ telnet y.y.y.y someport
Trying y.y.y.y...
telnet: Unable to connect to remote host: No route to host

tcpdump would give me:

$ sudo tcpdump -n host y.y.y.y -vv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
15:00:20.458957 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has y.y.y.y tell my.elastic.ip.something, length 28
15:00:21.457707 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has y.y.y.y tell my.elastic.ip.something, length 28
15:00:22.457673 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has y.y.y.y tell my.elastic.ip.something, length 28

After some days researching I found this mailinglist thread which shed some light on the issue.

Switching leftsourceip from $ELASTIC_IP to my private IP on the /etc/ipsec.d/connection_name.conf solved the issue.

EDIT: I know, this removes the assumption that private EC2 address doesn't matter, but it was the only way I got this to work.

@asinghal
Copy link

asinghal commented Jul 5, 2016

This approach worked out of the box beautifully for me. But to route traffic from other servers using this only as a VPN gateway, you need NAT rules. The one that works for me is

iptables -t nat -A POSTROUTING -s $SOURCE_CIDR  -j SNAT --to $GATEWAY_IP

That way, the right side only needs to know the gateway IP address

@joliving
Copy link

Thanks for the write up. I am able to create the tunnel and left vpn server is able to ping the right side subnet. But my problem is left side subnet is not able to ping the right. I have issue with iptables in left vpn server.

@kdjomeda
Copy link

@barboni. I am sure by now you figured out everything but I have been keeping a blog off late and I wrote about VPN recently. You might want to have a look at www.mycodingpains.com

@lorenzocipriani
Copy link

Hi @winhamwr.
It's a worth to mention that at this step:

Test the Connection

To test the connection, run the following command (replacing $CONN_NAME with the appropriate value):
$ sudo ipsec auto --up $CONN_NAME

It may be required to run this command first:
$ sudo ipsec auto --add $CONN_NAME
in case the --up command raises an error like
021 no connection named $CONN_NAME

@Dhariaj
Copy link

Dhariaj commented Jul 30, 2018

We have used this method and got the tunnel up. I configured a script to netcat a host on the other end but intermittently netcat fails and the ipsec service has to be restarted. I am not sure if someone else has the same issue and if there are any suggestions?

@devopsclm
Copy link

Hi!,

We have the same problem with VPN.
We have a 3 servers, APP. VPN and INFO. The tunnel is up but We can't reach for INFO

APP Subnet: 172.31.15.0/20 . IP private: 172.31.15.114 (AWS)
VPN Subnet: 172.31.19.0/20. IP private: 172.31.19.136 (AWS)
INFO Subnet: 192.168.0.0/23 IP private: 192.168.1.1

INFO can reach to 172.16.15.114 but APP can't reach to 192.168.1.1

Can anybody help us , please?

@devopsclm
Copy link

After searching and reading many forums, we have solved the problem by modifying the ipsec.conf file as follows:
Remove '#'

    nat_traversal=yes               
    virtual_private=%v4:172.31.15.0/24,%v4:192.168.0.0/23,%v4:!172.31.29.0/20  #Add subnets. !=Don't use subnet

Regards

@arunbakshi
Copy link

arunbakshi commented Aug 27, 2021

Need help on OpenSwan Dynamic Site to Site VPN setup AWS

I was trying to set up an OpenSwan Dynamic Site to Site VPN setup in AWS but my tunnel was not coming up and after a lot of research I found your article. I have configured the setup as you have mentioned and i am getting the below output when i check the connection but still my AWS VPN tunnel is showing down 
117 "aws_vpn.conf" #3: STATE_QUICK_I1: initiate
004 "aws_vpn.conf" #3: STATE_QUICK_I2: sent QI2, IPsec SA established tunnel mode

In AWS VPN Tunnel is showing down but IPSEC is UP. How to get around this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment