When we configure a zone-based firewall, we place interfaces into security zones. All our policies reference zones instead of interfaces, in this way we can add interfaces to a zone without configuring a whole bunch of new roles. It’s a fairly common way of implementing a firewall, with Juniper also using the concept of security zones in their SSG and SRX lines.
Zone-based firewall features:
• Stateful inspection
• Application inspection
• Packet filtering
• URL filtering
• Transparent firewall
• Support for virtual routing ad forwarding (VRF)
• ACLs are not required as a prerequisite for the policy
Interfaces can only belong to a single zone. There also exists a self-zone which is used for any traffic destined for the router itself. Once we place an interface in a zone, no traffic is allowed from that zone to any other zone unless we specifically permit it. However all traffic is allowed between interfaces in the same zone. To allow traffic between zones, first we create a zone-pair, which identifies the source and destination zones and applies a policy to traffic which matches that zone pair.
That is all fairly generic information for a zone-based firewall, so let’s see how this works on a Cisco IOS router.
•
Class maps – This is what will identify the traffic. Traffic can be matched on anything from layer 3 through to layer 7 of the OSI model, and it can refer to ACLs to identify traffic. A class map consists of match statements and can have multiple of those. We can also set it match all so that all statements have to match, or match-any, in which any of the statements can match.
•
Policy maps – These define the actions that are taken on the traffic. Policy maps are processed in order. The most common actions that can be taken are inspect, permit, drop or log.
•
Service policies – Where policies are applied from a policy map to a zone pair.
So let’s go ahead and create some policies apply to our configuration:
First let’s define a class map that will match on management traffic which we will define as telnet, ssh, https and icmp.
R1(config)#class-map type inspect match-any MGMTMAP
R1(config-cmap)#match protocol telnet
R1(config-cmap)#match protocol ssh
R1(config-cmap)#match protocol icmp
R1(config-cmap)#match protocol https
Now we need to define a policy map which calls on this class map.
R1(config)#policy-map type inspect MGMTPOLMAP
R1(config-pmap)#class type inspect MGMTMAP
R1(config-pmap-c)#inspect
Now let’s create our three zones:
R1(config)#zone security internal
R1(config-sec-zone)#exit
R1(config)#zone security external
R1(config-sec-zone)#exit
R1(config)#zone security dmz
R1(config-sec-zone)#exit
Now we need to create a zone-pair and apply a policy map to it:
R1(config)#zone-pair security in-to-dmz source internal destination dmz
R1(config-sec-zone-pair)#service-policy type inspect MGMTPOLMAP
The last step we need to configure is to place the interfaces in their correct zones:
R1(config)#int g2/0
R1(config-if)#zone-member security internal
R1(config-if)#exit
R1(config)#int f1/0
R1(config-if)#zone-member security dmz
R1(config-if)#exit
R1(config)#int f0/0
R1(config-if)#zone-member security external
What we have created here is to allow the internal network to access the DMZ only on telnet, ssh, https and icmp, so let’s give it a test: (note that I’ve changed to using routers in GNS3 to act as end devices, Virtualbox was killing my machine!)
InternalRTR#ping 172.16.31.20
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 172.16.31.20, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 32/65/164 ms
InternalRTR#telnet 172.16.31.20 80
Trying 172.16.31.20, 80 ...
% Connection timed out; remote host not responding
InternalRTR#telnet 172.16.31.20
Trying 172.16.31.20 ... Open
We can see that ICMP and telnet are being allowed through, but port 80 is blocked.
We can also run a debug on the router to verify it is being blocked:
*Nov 27 10:41:58.151: FIREWALL*: NEW PAK 67181CE0 (0:192.168.21.20:52467) (0:172.16.31.20:80) tcp
*Nov 27 10:41:58.151: FIREWALL*: DROP feature object 0xAAAA0005 found
*Nov 27 10:41:43.247: FIREWALL* sis 67EF6240: L4 result: PASS packet 0x67181CE0 (192.168.21.20:22967) (172.16.31.
R1#20:22) bytes 24
Note that because we have not defined a zone-pair between the inside and outside networks, all traffic is allowed at this stage. We would need to follow a similar process to above to lock that down. There is a slight difference with the self-zone, where even if we define a zone-pair but have no policy in it, traffic will be allowed between the self-zone and any other zone, however with two regular zones, if we have a zone-pair defined with no policy then all traffic will be dropped.
We can also create all of this using the Cisco Configuration Professional interface; however I won’t be going into any of that configuration here. You can download the software from Cisco with a valid
So now let’s finish off this by securing the firewall to have the same access as we configured with the access-lists in an earlier post.
To recap this is the access to be allowed:
• Everyone on the internal network can access the Internet for web browsing
• Everyone on the internal network can access the DMZ but only for management (SSH, HTTPS and RDP)
• Everyone on the internet can only access the web server (172.16.31.20) but only on HTTP and HTTPS
So far we have configured access from the internal network to the DMZ for ssh, https, telnet and icmp so we need to change that configuration slightly.
R1(config)#class-map type inspect match-any MGMTMAP
R1(config-cmap)#no match protocol telnet
R1(config-cmap)#no match protocol icmp
R1(config)#ip access-list extended RDP
R1(config-ext-nacl)#permit tcp any any eq 3389
R1(config)#class-map type inspect MGMTMAP
R1(config-cmap)#match access-group name RDP
Now we should access from the internal to the DMZ locked down to just SSH, HTTPS and RDP:
*Nov 27 12:55:42.475: FIREWALL*: NEW PAK 67181CE0 (0:192.168.21.20:54688) (0:172.16.31.20:23) tcp
*Nov 27 12:55:42.475: FIREWALL*: DROP feature object 0xAAAA0005 found
*Nov 27 12:56:07.395: FIREWALL* sis 67EF6560: Pak 0x66F549FC IP: s=172.16.31.20 (FastEthernet1/0), d=192.168.21.20 (GigabitEthernet2/0), len 20, proto=tcp
*Nov 27 12:56:07.395: FIREWALL* sis 67EF6560: L4 result: PASS packet 0x66F549FC (172.16.31.20:3389) (192.168.21.20:11910) bytes 20
Let’s lock down our access for the outside now. Everyone should be able to access the web server, but only on http and https
R1(config)#ip access-list extended WEBACL
R1(config-ext-nacl)#permit ip any host 172.16.31.20
R1(config)#class-map type inspect match-any WEBMAPPORTS
R1(config-cmap)#match protocol http
R1(config-cmap)#match protocol https
R1(config-cmap)#exit
R1(config)#class-map type inspect match-all WEBMAP
R1(config-cmap)#match class-map WEBMAPPORTS
R1(config-cmap)#match access-group name WEBACL
R1(config-cmap)#exit
R1(config)#policy-map type inspect WEBPOLMAP
R1(config-pmap)#class type inspect WEBMAP
R1(config-pmap-c)#inspect
R1(config)#zone-pair security out-to-dmz source external destination dmz
R1(config-sec-zone-pair)#service-policy type inspect WEBPOLMAP
If we run through what we do above, we create an access-list only allowing traffic to the destination 172.16.31.20. Then we create a class map that will match on either http and https traffic. Now we create another class-map that will only match on both the destination IP and ports. The policy map then inspects that class map, and in turn the zone-pair inspects that policy map.
*Nov 27 14:27:03.839: FIREWALL* sis 675C3AA0: L4 result: PASS packet 0x66F549FC (172.16.31.20:80) (45.45.45.20:47585) bytes 20
*Nov 27 14:27:49.383: FIREWALL*: NEW PAK 66F54590 (0:45.45.45.20:30237) (0:172.16.31.20:22) tcp
*Nov 27 14:27:49.383: FIREWALL*: DROP feature object 0xAAAA000C found
Looks like our configuration is working – port 80 is accessible from the outside, but port 22 is blocked.
We can also use some show commands to have a look at what is happening on the firewall:
R1#show class-map type inspect
Class Map type inspect match-all WEBMAP (id 11)
Match class-map WEBMAPPORTS
Match access-group name WEBACL
Class Map type inspect match-any WEBMAPPORTS (id 10)
Match protocol http
Match protocol https
Class Map type inspect match-any MGMTMAP (id 1)
Match protocol ssh
Match protocol https
Match access-group name RDP
Note – I set up an SSH session from my internal device to my external device and then issued this command:
R1#show policy-map type inspect zone-pair in-to-dmz sessions
policy exists on zp in-to-dmz
Zone-pair: in-to-dmz
Service-policy inspect : MGMTPOLMAP
Class-map: MGMTMAP (match-any)
Match: protocol ssh
2 packets, 48 bytes
30 second rate 0 bps
Match: protocol https
0 packets, 0 bytes
30 second rate 0 bps
Match: access-group name RDP
0 packets, 0 bytes
30 second rate 0 bps
Inspect
Number of Established Sessions = 1
Established Sessions
Session 675C4720 (192.168.21.20:40743)=>(172.16.31.20:22) ssh:tcp SIS_OPEN
Created 00:00:39, Last heard 00:00:33
Bytes sent (initiator:responder) [251:403]
Class-map: class-default (match-any)
Match: any
Drop
2 packets, 48 bytes
The last thing to configure for this post is to get some NAT going. We haven’t set up anything for internal to external, so let’s configure it so that any host on the internal can get to any host on the outside network, but we’re only going to allow ssh, http, https, pop3, smtp and imap.
We’ll follow exactly the same process as before, class-map, policy-map, zone-pair. We’ll add the NAT right at the end.
R1(config)#class-map type inspect match-any INTOOUTMAP
R1(config-cmap)#match protocol http
R1(config-cmap)#match protocol https
R1(config-cmap)#match protocol ssh
R1(config-cmap)#match protocol smtp
R1(config-cmap)#match protocol imap
R1(config-cmap)#match protocol pop3
R1(config)#policy-map type inspect INTOOUTPOLMAP
R1(config-pmap)#class type inspect INTOOUTMAP
R1(config-pmap-c)#inspect
R1(config)#zone-pair security IN_TO_OUT source internal destination external
R1(config-sec-zone-pair)#service-policy type inspect INTOOUTPOLMAP
That should be enough to enable the ports out that we would like, now we just need to add the NAT configuration:
R1(config)#access-list 10 permit 192.168.21.0 0.0.0.255
R1(config-if)#int fa0/0
R1(config-if)#ip nat outside
R1(config)#int g2/0
R1(config-if)#ip nat inside
R1(config)#ip nat inside source list 10 interface fa0/0 overload
Now we should be able to ssh from our internal network to our external network and when it passes the router it should be translated to the outside interface of the router. Let’s give it a go:
R1#show policy-map type inspect zone-pair IN_TO_OUT sessions
policy exists on zp IN_TO_OUT
Zone-pair: IN_TO_OUT
Service-policy inspect : INTOOUTPOLMAP
Class-map: INTOOUTMAP (match-any)
Match: protocol http
1 packets, 24 bytes
30 second rate 0 bps
Match: protocol https
0 packets, 0 bytes
30 second rate 0 bps
Match: protocol ssh
1 packets, 24 bytes
30 second rate 0 bps
Match: protocol smtp
0 packets, 0 bytes
30 second rate 0 bps
Match: protocol imap
0 packets, 0 bytes
30 second rate 0 bps
Match: protocol pop3
0 packets, 0 bytes
30 second rate 0 bps
Inspect
Number of Established Sessions = 1
Established Sessions
Session 675C4D60 (192.168.21.20:64953)=>(45.45.45.20:22) ssh:tcp SIS_OPEN
Created 00:00:56, Last heard 00:00:14
Bytes sent (initiator:responder) [419:4351]
Class-map: class-default (match-any)
Match: any
Drop
13 packets, 592 bytes
Looks like it’s working as we’d expect, and indeed the SSH session is working from that router. Now let’s verify the NAT:
R1#show ip nat translations
Pro Inside global Inside local Outside local Outside global
tcp 45.45.45.1:64953 192.168.21.20:64953 45.45.45.20:22 45.45.45.20:22
We can see that the Inside local address is 192.168.21.20 which is the address of the internal device, and the inside global address is 45.45.45.1 which is the ip address of the central router’s external interface, so the NAT is indeed working.
One final check is to see what the external router is seeing:
ExternalRTR#show users
Line User Host(s) Idle Location
* 0 con 0 idle 00:00:00
2 vty 0 admin idle 00:03:01 45.45.45.1
It shows the user admin is logged on from 45.45.45.1, so it’s all working perfectly.
Well that was a fairly lengthy post, but it gives us some great practical knowledge on zone-based firewall. Next up we’re moving to the ASA.