Wednesday, February 23, 2011

Zone Based Firewall, PPTP pass-through

I am seeing many people migrating from Cisco CBAC to Zone Based Firewall (ZBF) on 800 - 3900 series ISR devices being used as Internet edge firewalls due to the greater flexibility, and better interoperability with policy routing.


The most common question I receive is from a tech that sets up Zone Based Firewall according to Cisco's guide and many examples on the Internet, then finds out clients on the inside are unable to use their PPTP Windows VPN to connect to a server outside the firewall.


I encourage anyone interested in a deep understanding of PPTP to read through RFC 2637, but I will give a quick summary of the pertinent aspects of PPTP here. It is important to understand that PPTP utilizes TCP port 1723 for connection establishment, authentication, and maintenance, it then uses GRE, IP protocol 47, to pass data. By default, ZBF's keyword "match protocol pptp" does not handle the GRE traffic, only the TCP 1723 traffic.


First, let's see how to migrate from CBAC to the most basic ZBF configuration


Exhibit 1: Most Basic ZBF Config

Everything except PPTP will work outbound with this config


Step 1: Define and populate our zones:

!Define two zones

zone security ZONE_INSIDE

zone security ZONE_OUTSIDE


interface fa0/1

!Assume FastEthernet0/1 is our inside interface

zone-member security ZONE_INSIDE


interface fa0/0

!Assume FastEthernet0/1 is our outside interface

zone-member security ZONE_OUTSIDE

!Remove any CBAC commands you had here

no ip inspect CBAC in

no ip inspect CBAC out

!Remove the inbound access-list from the outside interface. Unlike CBAC, we do not control inbound access via an access-list.

no ip access-group ACLin in


Step 2: Define the class maps that identify traffic that is permitted between zones:

class-map type inspect match-any CM_INTERNET_TRAFFIC

match protocol h323

match protocol pptp

match protocol ftp

match protocol tcp

match protocol udp

match protocol icmp

!Note - we add h323 and ftp here specifically to account for upper-layer inspection required for those protocols


Step 3: Configure a policy map which specifies the action for the class map:

policy-map type inspect PM_INSIDE_TO_OUTSIDE

class type inspect CM_INTERNET_TRAFFIC

inspect


Step 4: Configure the zone pair and apply your policy:

zone-pair security ZONEP_INSIDE_OUTSIDE source ZONE_INSIDE destination ZONE_OUTSIDE

service-policy type inspect PM_INSIDE_TO_OUTSIDE




Exhibit 2: I like PPTP, would like!

This config adds outbound PPTP. Note – GRE is not automatically opened by the “match protocol pptp” in the CM_INTERNET_TRAFFIC, so we need to make GRE passed both inside to outside and reverse without inspecting it.


Step 1, Define new class-map that matches all GRE, note that you need to use an ACL for this that is referenced in the class-map:

ip access-list extended GRE

remark Access List to allow PPTP GRE outbound

permit gre any any

class-map type inspect match-any CM_GRE_PROTOCOLS

match access-group name GRE


Step 2: Configure a policy map which specifies the action for the class map:

policy-map type inspect PM_INSIDE_TO_OUTSIDE

class type inspect CM_GRE_PROTOCOLS

pass

class type inspect CM_INTERNET_TRAFFIC

inspect

class class-default

drop


policy-map type inspect PM_OUTSIDE_TO_INSIDE

class type inspect CM_GRE_PROTOCOLS

pass

class class-default

drop


Step 3: Configure the zone pair and apply your policy:

zone-pair security ZONEP_INSIDE_OUTSIDE source ZONE_INSIDE destination ZONE_OUTSIDE

service-policy type inspect PM_INSIDE_TO_OUTSIDE


zone-pair security ZONEP_OUTSIDE_INSIDE source ZONE_OUTSIDE destination ZONE_INSIDE

service-policy type inspect PM_OUTSIDE_TO_INSIDE


Note: The above config is perfect for a SOHO user who is not hosting any internal servers. However, most sites will be hosting servers internally, so below is an example with the naming scheme of how I like to form my class maps, access-lists, and policy-maps. Note that I like to keep all "variable" names in upper case so they pop out to me in my config. (Credit to Internetwork Experts for that tip)


Exhibit 3: I host servers, so I need an inbound firewall


Step 1, Define an access-list with the internal IP of the server:

ip access-list extended HELPDESK

permit ip any host 10.5.0.3


Step 2, Define a "match-any" class-map with the protocols to be allowed:

class-map type inspect match-any CM_HELPDESK_PROTOCOLS

match protocol http

match protocol https

match protocol ssh


Step 3, Define a "match-all" class map to combine the two:

class-map type inspect match-all CM_HELPDESK

match access-group name HELPDESK

match class-map CM_HELPDESK_PROTOCOLS


Step 4, Add the class-map to the OUTSIDE_TO_INSIDE policy-map:

policy-map type inspect PM_OUTSIDE_TO_INSIDE

description Internet to LAN Servers

class type inspect CM_GRE_PROTOCOLS

pass

class type inspect CM_ICMP

inspect

class type inspect CM_HELPDESK

inspect

class class-default

drop


Step 5, Don't forget your nat statement:

ip nat inside source static 10.5.0.3 1.1.1.1



Notes:

  1. I like to add an ICMP inspect class map so you can ping all servers without needing to explicitly adding ICMP to every server's class-map. You would not want this if permitting pinging is not preferred, or if you are worried about ICMP security risks.
  2. If you need to add a non-standard port you have two options.
    1. First, give it a name: ip port-map user-RDP port tcp 3389
    2. Second, define an ACL with the ports, and add it to the "match-any" CM_SERVER_PROTOCOLS:

ip access-list extended LTIITEDGE_PROTOCOLS

permit tcp any host 10.50.1.10 eq 5061

permit tcp any host 10.50.1.10 eq 8057

permit tcp any host 10.50.1.10 eq 5062

permit tcp any host 10.50.1.10 eq 3478

permit tcp any host 10.50.1.10 range 49152 65535


DocCD items to reference:

Zone-Based Firewall Configuration Guide