Cisco Zone Based Firewall (IPv4 & IPv6)
Introduction:
I don't like security. It just gets in the way when you're trying to get stuff done. But that is no excuse to have nothing in place!
I typically trust NAT, and don't tend to operate with much in the way of firewalling on home router setups. NAT will implicitly block inbound connections to stuff - because your internal addressing is not routable. That's not to say you shouldn't have any security, VTY ACLs on routers are especially important, and blacklists for nasty stuff are also useful.
So why bother now? Simply put, IPv6. IPv6 is publicly routable, so as soon as you've got it you have to have some way of securing your devices. Given the number of IPv6 addresses which an attacker would have to scan to find something vulnerable it's fairly unlikely. But what happens if they get your IP from some service you're using? Without any firewall in place, they can connect straight to it and any services you're running! Not good.
Solution:
Zone Based Firewall. I am a fan of the Context Based Access Control (CBAC) firewall (because it's simple and I don't like security). However the platform I am using no longer supports it, and it really is worth using something a bit more up to date.
First, define the zones you want. I have two, Inside and Outside. Inside is for LAN and Outside for WAN, pretty straightforward!
zone security Inside
zone security Outside
Let's now focus on outbound communications. Inbound communications are only required if you've got servers or services running within your network you want to expose.
Define the protocols you want to allow outbound in a class-map. Mine are generic because I just want to allow everything out.
class-map type inspect match-any Outbound_Protocols
match protocol tcp
match protocol udp
match protocol icmp
Now we define policy maps to allow communication. It's worth noting that I have an Inside-Inside policy to allow communication explicitly, so I can modify it in future if required.
We inspect outbound protocols, so any return traffic will be allowed without having to match an inbound policy. This is why we need stateful!
policy-map type inspect Inside_Policy
class class-default
pass
policy-map type inspect Inside_to_Outside_Policy
class type inspect Outbound_Protocols
inspect
class class-default
drop
Define the zone pairs, and then we can attach our policy maps:
zone-pair security Inside-Inside source Inside destination Inside
service-policy type inspect Inside_Policy
zone-pair security Inside->Outside source Inside destination Outside
service-policy type inspect Inside_to_Outside_Policy
Finally, don't forget to associate the zones with interfaces! In this example I don't actually have multiple Inside zone members, so could have omitted the Inside-Inside zone pair and associated policies. Doesn't hurt to keep it though.
interface gig0/0/1
zone-member security Outside
interface vlan20
zone-member security Inside
Now, what about if we're running services internally? We need to define a path for traffic to get in without having an existing inspection entry.
First, define an ACL with the entries you need to permit. In my case I permit VPN traffic, as well as HTTP and HTTPS (in my case this blog).
ip access-list extended ACL_Inbound_Protocols
1 permit udp any any eq isakmp
2 permit udp any any eq non500-isakmp
3 permit esp any any
4 permit ahp any any
10 permit tcp any any eq 443
20 permit tcp any any eq 80
Note: You MUST have the corresponding NAT entries configured already! If you don't then your service won't work before the firewall rules are in place!
Make sure that your port numbering in the above ACL uses the internal port number as NAT happens first. I.e. if you're hosting a webserver internally on port 80, but exposing it to the world on port 8080, you must use port 80 in your ACL!
Now it's the same structure as before, class-map first. We match the ACL above.
class-map type inspect match-any Inbound_Protocols
match access-group name ACL_Inbound_Protocols
Then the policy-map:
policy-map type inspect Outside_to_Inside_Policy
class type inspect Inbound_Protocols
inspect
class class-default
drop
Then finally the zone-pair. You need a zone-pair for each direction:
zone-pair security Outside->Inside source Outside destination Inside
service-policy type inspect Outside_to_Inside_Policy
That's it! Done!
...wait a second, what about IPv6?!
It's actually super easy, it's already working! If you've got IPv6 up and running, you'll notice you can no longer reach internal addressing from the outside world, awesome!
If you need to pinhole specific stuff, so you can get access to servers etc, we'll have to add another ACL. Mine's denying everything explicitly as a placeholder for future services.
ipv6 access-list ACL_Inbound_Protocols_v6
<permit stuff here>
deny ipv6 any any
Then all you've got to do, is modify the Inbound protocols class-map, from this:
class-map type inspect match-any Inbound_Protocols
match access-group name ACL_Inbound_Protocols
To this:
class-map type inspect match-any Inbound_Protocols
match access-group name ACL_Inbound_Protocols
match access-group name ACL_Inbound_Protocols_v6
Done! How easy is that!
Verification Commands:
There's a few commands to verify and check things - these work rather nicely for the basics:
show policy-map type inspect zone-pair
show policy-firewall stats global
show zone-pair security
show zone security
show policy-firewall sessions platform
Final Configuration (If you don't host anything internally):
class-map type inspect match-any Outbound_Protocols
match protocol tcp
match protocol udp
match protocol icmp
policy-map type inspect Inside_Policy
class class-default
pass
policy-map type inspect Inside_to_Outside_Policy
class type inspect Outbound_Protocols
inspect
class class-default
drop
zone security Inside
zone security Outside
zone-pair security Inside-Inside source Inside destination Inside
service-policy type inspect Inside_Policy
zone-pair security Inside->Outside source Inside destination Outside
service-policy type inspect Inside_to_Outside_Policy
Final Configuration (If you do host stuff):
class-map type inspect match-any Outbound_Protocols
match protocol tcp
match protocol udp
match protocol icmp
class-map type inspect match-any Inbound_Protocols
match access-group name ACL_Inbound_Protocols
match access-group name ACL_Inbound_Protocols_v6
ip access-list extended ACL_Inbound_Protocols
!<add permit statements for internal services>
!<remember that NAT happens first!>
ipv6 access-list ACL_Inbound_Protocols_v6
!<add permit statements for internal services>
policy-map type inspect Inside_Policy
class class-default
pass
policy-map type inspect Inside_to_Outside_Policy
class type inspect Outbound_Protocols
inspect
class class-default
drop
policy-map type inspect Outside_to_Inside_Policy
class type inspect Inbound_Protocols
inspect
class class-default
drop
zone security Inside
zone security Outside
zone-pair security Inside-Inside source Inside destination Inside
service-policy type inspect Inside_Policy
zone-pair security Inside->Outside source Inside destination Outside
service-policy type inspect Inside_to_Outside_Policy
zone-pair security Outside->Inside source Outside destination Inside
service-policy type inspect Outside_to_Inside_Policy