---
layout: post
title: Basic road warrior VPN using a Cisco router
date: 2015-12-27
tags: ["cisco","General","ipsec","security","vpn"]
---

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](https://twitter.com/gothmog/) 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](https://strongswan.org) 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](http://www.cisco.com/c/en/us/products/collateral/routers/2800-series-integrated-services-routers-isr/product_data_sheet0900aecd8016fa68.html) 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:

1.  [IPsec](https://tools.ietf.org/html/rfc2401)
2.  Capable of supporting iOS and Mac OS X clients
3.  Clients could be behind NATs ([NAT-T](https://tools.ietf.org/html/rfc3715) support)
4.  Pre-shared Key support (I might do certificates again later, but as there are only 2 users of the VPN, seems like overkill.)
5.  _All_ traffic from the clients will be routed through the VPN (no split-tunnels)
6.  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.

1.  You are familiar working in the IOS command line interface
2.  You already have a working network
3.  It has a single external IP address (preferably a static IP)
4.  You have 1 (or more than 1) internal networks
5.  Internal hosts are NAT translated when communicating with the Internet
6.  You are familiar with setting up your `ip access-list` commands 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](https://tools.ietf.org/html/rfc2408) 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

## IPSEC Paramaters

We set up the paramaters that define how IOS _transforms_ (aka, encrypts and HMACs) the traffic on this tunnel and give it a name `vpn-transform-set`

    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 `FastEthernet0/0`.

    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

## Other Notes

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)](https://tools.ietf.org/html/rfc2408)
*   ESP Packets - IP Protocol 50 - [IP Encapsulating Security Payload (ESP)](http://tools.ietf.org/html/rfc4303) - 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

## Client Setup

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

## Final Notes

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](https://twitter.com/gothmog)
