VPN With Amazon EC2 or Saving Your Phone From Promiscuity

Modern mobile devices are a wonderful, especially when combined with some handy public WiFi hotspot. Unfortunately ne’er-do-wells abound so if you aren’t careful using public hotspots, people can poke around with your data packets and steal fun details like usernames and passwords. What is a mobile internet addict to do?

Simple! Setup up your own VPN. Here’s how to set one up on Amazon EC2, suitable for use with most smartphones and laptops.

Pre-requisites

Similar to my Reviewboard setup guide this one assumes that you have an AWS EC2 account, and that you are comfortable with creating instances and ssh‘ing into them.

I’m assuming you are installing this on an Amazon Linux AMI EC2 instance, but it will probably work with other Linux distributions. If you’re lucky, all you will need to do is substitute that distribution’s package manager command in place of yum. For example, apt-get.

The resulting VPN supports PPTP connections which, while not the most secure, are probably the most widely supported. Android, iOS, Linux, Windows 7 and Mac OS X all come with PPTP VPN clients.

What You’ll End Up With

  • 1 (one) VPN PPTP daemon (Poptop) running on the server
  • n (many) VPN user accounts, as desired
  • 1 (one) more secure way to access the internet

Optionally, you will also have a script which allows you to easily add new VPN accounts.

Installing and configuring PPTPD

Install all the stuff for the PPP daemon (PPTP uses this) and some development tools for compiling Poptop. As usual, you don’t type (and don’t copy) the $ symbol at the start of the line, I just use that to indicate the command prompt, but you can include the \ line splitting characters when copying and pasting:

$ sudo yum --assumeyes install \
    ppp \
    ppp-devel \
    make \
    gcc \
    gcc-c++ \
    openssl-devel \
    ntsysv

Fetch and extract Poptop:

$ mkdir ~/pptpd-install
$ cd ~/pptpd-install
$ curl -s http://kent.dl.sourceforge.net/project/poptop/pptpd/pptpd-1.3.4/pptpd-1.3.4.tar.gz | tar -xvz

Configure Poptop to use the /usr directory when it’s installed. I did this to get around a few issues with paths in the default configuration (alternatively I could have edited those, but I’m lazy):

$ cd pptpd-1.3.4
$ ./configure --prefix=/usr --exec-prefix=/usr

Next we want to patch the patchlevel.h file so that wtmp logging works. It’s a bit of a hassle, but I think it’s worth it because you can the use standard wtmp reading commands such as last venger to see a list of when and where VPN user venger connected. Handy if you ever suspect someone has been misusing your account.

This crazy command gets the current pppd version and uses sed to substitute that version in the plugins/patchlevel.h file:

$ PPPD_VERSION=$(pppd -v 2>&1 | grep -E '^.*version.*$' | gawk '{print $3}'); \
    sed -ie 's/\(.*VERSION.*"\)\(.*\)\(".*\)/\1'$PPPD_VERSION'\3/' \
    plugins/patchlevel.h

Now make and install Poptop:

$ sudo make install

Add an init script so that we can set it to start automatically later:

$ sudo cp pptpd.init /etc/init.d/pptpd
$ sudo chmod 755 /etc/init.d/pptpd

Copy the basic configuration file for pptpd and specify the local IP address range to be used for connected clients. NOTE: you cannot have more users connected simultaneously than the range specified here, which covers 100 IP addresses. The range you give it must be from the private IP address block, and must not conflict with other addresses on that machine or the LAN to which it’s connected or Bad Things may happen.

$ sudo cp samples/pptpd.conf /etc/pptpd.conf
$ echo -e "localip 192.168.69.254\nremoteip 192.168.69.1-101" \
    | sudo tee --append /etc/pptpd.conf

Now copy the sample PPP options for PPTP connections and modify it a little to specify a few useful things.

The first echo‘d line sets Google’s public DNS servers as the DNS servers used to resolve web addresses when you are using the VPN connection. If you don’t want to use Google’s public DNS servers, then you could use the public DNS servers provided by OpenDNS (208.67.222.222 and 208.67.220.220), or find your own alternatives.

The second echo‘d line adjusts the MTU and MRU. A side effect of the way VPN wraps data may cause data packets to exceed 1500 octets, causing frequent disconnects for some. Setting this to 1400 should avoid that. It’s likely you can get away with using 1492 but that was causing me some issues with my connection, so 1400 is playing it very safe:

$ sudo cp samples/options.pptpd /etc/ppp/options.pptpd
$ echo -e "\n# Google DNS\nms-dns 8.8.8.8\nms-dns 8.8.4.4\n" \
    | sudo tee --append /etc/ppp/options.pptpd
$ echo -e "\n# Make MTU/MRU a little smaller than default\nmru 1400\nmtu 1400" \
    | sudo tee --append /etc/ppp/options.pptpd

Configuring NAT and Fixing Your EC2 Firewall

That’s it for the basic PPTP configuration, but now you have to modify your iptables rules and kernel settings so that your instance knows to forward data to the correct client when connected via VPN.

First, adjust the iptables rules and save them so it all works after reboot:

$ sudo iptables -t nat -A POSTROUTING -s 192.168.69.0/24 -j MASQUERADE
$ sudo service iptables save

And now make sure your kernel knows that you want to use NAT. The sed command here is modifying your sysctl.conf so that your system remembers to enable NAT on reboot:

$ sudo sysctl net.ipv4.ip_forward=1
$ sudo sed -i -r 's/(net.ipv4.ip_forward)(.*)0$/\1\21/' /etc/sysctl.conf

In order to connect to your EC2 instance from the outside world, you will have to open up the correct port, 1723, in the security group. The easiest way to do this is from the Amazon AWS EC2 web console.

Log in to your AWS account, go to the EC2 tab, select the Security Groups section and then select the security group for the instance you have installed the VPN on:

Now add a custom TCP rule for port 1723 to make it available to everyone. If you want to limit which IP address ranges can connect to your VPN, use the appropriate CIDR source specifier. I want to access it from unknown public IP addresses so I’m setting it to accept connections from all IP address, 0.0.0.0/0:

Also add a custom UDP rule with the same details. I’m not entirely certain that VPN connections support UDP, but what the hell. NOTE: Don’t forget to click Apply Rule Changes near the bottom of the inbound rule pane before leaving the page. I often miss that.

Starting Everything Up

Now lets make sure all the services we just set up are started, and that they restart when the instance is rebooted:

$ sudo chkconfig iptables on
$ sudo chkconfig pptpd on
$ sudo service iptables restart
$ sudo service pptpd stop     # Should fail, but just in case...
$ sudo service pptpd start

Adding Users

All that’s left to do now is to add a VPN user. I prefer to add a VPN user for each device which uses VPN. If the device is ever stolen or lost, having a different user for each allows me to block access for that device by removing the user entry.

To add a user, you must append a user entry to the /etc/ppp/chap-secrets file with the correct format. The format it expects is defined as:

[username] [vpn_service_name] [password] [allowed_ip_addresses]

You can quickly add a user with the following verbose command. Remember to change USERNAME to your desired username. The section starting dd in the echo string generates a random password for the user which will be shown at the end. I recommend treating this as a once only password – just copy or email the password to the device and paste the password into your VPN client setup and tell it to remember the password. If you ever think it’s compromised, just delete the user or generate a new password. Avoid using the same password for multiple users. Don’t forget to eat the email you sent with the password. Eat your vegetables.

echo -e "\nUSERNAME pptpd $(dd if=/dev/urandom count=1 2> /dev/null | sha1sum | cut -c-32) *\n" \
    | sudo tee --append /etc/ppp/chap-secrets

To delete a user, simply remove the line with their name from /etc/ppp/chap-secrets using your favourite text editor running as root. Pro Tip: Real Beings use vim.

Using that command to add each user is a bit of a faff, so I’ve written a script to make adding users easier. It will also check if a user already exists before adding a new one and just display the password instead. Here’s a sample session where I enter the same user twice:

$ sudo ./nah_vpn_add_user.sh venger

  Creating VPN user in '/etc/ppp/chap-secrets'

              username: venger
              password: 5fac76dfc049ea0f6e7b50c0641cc8c8
      VPN service name: pptpd

$ sudo ./nah_vpn_add_user.sh venger

  ERROR: User already seems to exist in '/etc/ppp/chap-secrets'

      username: venger
      password: 5fac76dfc049ea0f6e7b50c0641cc8c8

Here’s the script as a gist on github if you want to use it. As with every script a stranger gives you, and especially since I’m making you sudo this script, examine it to make sure I’m not doing anything evil to your system (I’m not, but I would say that):

You can download it to your machine and make it executable by typing:

$ curl https://raw.github.com/gist/1626638 -o nah_vpn_add_user.sh
$ chmod a+x nah_vpn_add_user.sh

And then add users to your hearts content. Running the script with no parameters will output some help. The script will only add users – deletion is still manual as described above (delete the user’s entry in /etc/ppp/chap-secrets).

Setting Up The Device Client

This guide is already far too long, so here are some links to other guides about setting up your client or clients. The main points to remember when following these guides are:

  • Protocol: Only use PPTP
  • Server Address: The public address or public IP of the EC2 Instance. This can change each time you boot, so you may want to assign an Elastic IP address to the instance or perhaps use Route 53.
  • Username: The username used when you created the user above.
  • Password: The generated password displayed when you created the user above.
  • Encryption Level: Should work as 128 bit or maximum, but you can try auto.

The guides (I don’t endorse any here and haven’t used any of the VPN services who’s guides I’ve linked here, but it’s handy information):

Checking the Connection

Once you have your client configured, connect to your new VPN and visit:

If all is well you should be able to see the site and it should say that your ISP is Amazon. Well done! You have a shiny new VPN to play with.

Points of Interest

It’s not just when you are using public hotspots that VPNs are useful. It will prevent, for example, your ISP inspecting what services you use or what websites you visit. Before you start merrily torrenting every legal thing in existence though, remember you’re paying for the bandwidth passing through your EC2 server. Also remember that while your ISP can’t see what addresses you visit, Amazon can.

Additionally, your VPN machine’s public IP address will be what the world sees. So if you set up a VPN machine at one of Amazon’s US datacenters then sites you visit will think you are a visitor from America. Or if you set one up in the EU, it will appear as though you come from Ireland.

Also, if anyone’s crazy enough to pass SOPA style regulations in your country, using a VPN in a datacenter outside your country may help, assuming Amazon, Google and OpenDNS aren’t affected directly by the legislation.

Have fun.

Comments