Welcome to another of my end of the year, oh-god-I-didn’t-blog-all-year posts. I’ve been trying to go through some of the geeky things I did this year that were a challenge for me and document them so that they might be easier for someone else.
Today’s topic: setting up a VPN server using a Cisco router for “road warrior” clients (aka, devices which could be coming from any IP address).
As should come to no surprise to anyone who knows me or who is exposed to my twitter stream I value privacy and security both from a philosophical perspective but also just as fun projects to tackle.
This project arose as an evolution of earlier VPN setups I have had in the past. When I was living in the linux world (and before I purchased my Cisco router), I used a linux server as my internet router. If you are in that situation, I highly recomend using the strongSwan VPN server. It is an enterprise grade VPN server that is also easily configured to handle small situations. I often had multiple VPN tunnels up for fixed connections that were both site to site and for roadwarriors using both pre-shared keys (PSK) and X509 certificates.
But when I upgraded our home network to using a Cisco 2811 router that I bought from a tech company liquidation auction for $11.57, running the strongSwan VPN from behind the NAT router became much more challenging. (Doable, but required some ugly source routing hacks I never liked.)
My requirements were:
- Capable of supporting iOS and Mac OS X clients
- Clients could be behind NATs (NAT-T support)
- Pre-shared Key support (I might do certificates again later, but as there are only 2 users of the VPN, seems like overkill.)
- All traffic from the clients will be routed through the VPN (no split-tunnels)
- Ability to to do hairpin routing. (This means that a VPN client can tunnel all of their traffic, including that destined to the rest of the internet, to the VPN server and it will be able to route it back out to the internet. This is critical for protecting your clients on untrusted networks.)
The biggest challenge that I ran into was not the lack of capabilities of the Cisco platform, but the fact that it is designed for much much larger implementations that I was going to do. In addition, most of the examples were for site-to-site configurations.
I don’t intend to go through all of the steps needed to set up a Cisco router, that is beyond the scope of this post, so I will be making the following assumptions.
- You are familiar working in the IOS command line interface
- You already have a working network
- It has a single external IP address (preferably a static IP)
- You have 1 (or more than 1) internal networks
- Internal hosts are NAT translated when communicating with the Internet
- You are familiar with setting up your
ip access-listcommands to protect yourself and allow the appropriate traffic in and out of your networks
OK, let’s go!
Note: For my setup,
FastEthernet0/0 is my external interface (set up as
ip nat outside)
User & IP address setup
Set up a user (or more than one) that will be used to access the VPN.
aaa new-model aaa authentication login AUTH local aaa authorization network NET local username vpn-user password 0 VERY-STRONG-PASSWORD
And set up a pool of IP addresses that will be given out to users who connect to the VPN.
ip local pool VPN-POOL 10.42.40.0 10.42.40.255
ISAKMP Key Management
ISAKMP is the protocol that is used to do the initial negotiation and set up keys for the VPN session. First we will set up more general settings such as the fact we will be using 256 bit AES, PSKs, keepalives, etc.
crypto isakmp policy 1 encr aes 256 authentication pre-share group 2 lifetime 3600 crypto isakmp keepalive 10
We will then set up the group which represents our clients. This includes setting paramaters for your clients, such as the pool of IP addresses they will get (from above), DNS servers, settings for perfect forward secrecy (PFS), etc.
crypto isakmp client configuration group YOUR-VPN-GROUP key VERY-STRONG-GROUP-KEY dns YOUR-DNS-SERVER-IP domain YOUR-DOMAIN pool VPN-POOL save-password pfs netmask 255.255.255.0
Finally, we will pull these items into a profile,
vpn-profile, that can be used to set up a client.
crypto isakmp profile vpn-profile match identity group YOUR-VPN-GROUP client authentication list AUTH isakmp authorization list NET client configuration address respond client configuration group YOUR-VPN-GROUP virtual-template 1
We set up the paramaters that define how IOS transforms (aka, encrypts and HMACs) the traffic on this tunnel and give it a name
crypto ipsec transform-set vpn-transform-set esp-aes esp-sha-hmac
Full IPSEC profile
Finally we link both the ISAKMP (
vpn-profile) and IPSEC (
vpn-transform-set) items together and give them a name
ipsecprof that can be attached to a virtual interface (below).
crypto ipsec profile ipsecprof set transform-set vpn-transform-set set isakmp-profile vpn-profile
Virtual Template Interface
This caused me a bunch of confusion. Because we do not have a static site-to-site tunnel, we can’t define a tunnel interface for our VPN clients. What we do is set up a template interface that IOS will use to create the interfaces for our clients when they connect.
This needs to reference your external interface, which in my case is
interface Virtual-Template1 type tunnel ip unnumbered FastEthernet0/0 ip nat inside ip virtual-reassembly tunnel source FastEthernet0/0 tunnel mode ipsec ipv4 tunnel protection ipsec profile ipsecprof
It is important that you have the appropriate access controls set up to restrict where in your network a VPN client can send packets. That is really beyond the scope of this post as it is very dependent on your configuration.
However, at a minimum, you need to allow the packets that arrive on your external interface for VPN clients to be handled. These packets will show up in a few forms.
- ISAKMP packets - UDP port 500 - Internet Security Association and Key Management Protocol (ISAKMP)
- ESP Packets - IP Protocol 50 - IP Encapsulating Security Payload (ESP) - for clients not behind a NAT
- NAT-T Packets - UDP port 4500 - These are UDP encapsulated ESP packets for clients behind a NAT
You will need to add rules to handle these packets to your external, border, access lists.
ip access-list extended inBorder permit esp any host YOUR-EXTERNAL-IP permit udp any host YOUR-EXTERNAL-IP eq isakmp permit udp any host YOUR-EXTERNAL-IP eq non500-isakmp
Assuming all of this worked (and I transcribed things properly), you will be all set to configure a client. This should be a relatively easy configuration.
- VPN Type: IKEv1, in iOS/Mac OS X this is listed as Cisco IPsec or IPsec
- Server: Your public server IP or hostname
- Group: YOUR-VPN-GROUP
- Pre shared key: VERY-STRONG-GROUP-KEY
- User: vpn-user
- Password: VERY-STRONG-PASSWORD
Even though this setup uses users that are hard coded on your router, you may still want to set up a Radius server to receive accounting information so you can track connections to your VPN. It can also be expanded to do authentication and authorization for your VPN users.
I hope this was helpful to you. If you have any questions, please feel free to contact me via twitter @gothmog