Traditional firewall configurations on Cisco routers relied on Access Control Lists and Context-Based Access Control (CBAC) applied directly to interfaces. It worked, but it was messy. ACLs are stateless by nature, CBAC defaulted to allowing everything, and as networks grew more complex, the per-interface model became increasingly difficult to manage and audit.
In 2006, Cisco introduced the Zone-Based Policy Firewall (ZPF) in IOS 12.4(6)T. It replaced the interface-centric model with a zone-centric one, flipped the default policy to deny-all, and gave network engineers a configuration language that actually reads like a security policy.
Why ZPF Replaced CBAC#
The shift was not incremental. ZPF fundamentally changed how Cisco routers handle firewall policy.
| Feature | CBAC | ZPF |
|---|---|---|
| Default policy | Allow all | Deny all |
| Configuration model | ACL-based, per-interface | Zone-based with C3PL (Cisco Common Classification Policy Language) |
| Depends on ACLs | Yes | No |
| Readability | Complex, hard to audit | Clean, structured, easy to troubleshoot |
The biggest change is the default stance. CBAC allowed all traffic unless you explicitly configured inspection rules. If you forgot to configure something, traffic flowed freely. ZPF takes the opposite approach: everything is blocked unless you create a policy that explicitly permits it. If you forget something, traffic gets dropped. That is a much safer failure mode.
How Zones Work#
A zone is a logical grouping of interfaces that share the same security requirements. Instead of applying policies to individual interfaces, you define zones and then create policies for traffic moving between them.
Zone Membership Rules#
- Interfaces are assigned to zones. Policy applies to traffic flowing between zones
- Interfaces in the same zone communicate freely with no filtering
- Multiple interfaces can belong to one zone, but one interface can only belong to one zone
- A new interface added to a zone inherits that zone's characteristics
- If an interface is the only member of a zone and no zone-pair exists, all traffic is dropped
That last point catches people off guard. Assigning an interface to a zone without creating any zone-pairs effectively kills all traffic on that interface. The deny-all default is absolute.
The Self Zone#
Every router has a system-defined zone called the self zone. It represents the router itself, not the traffic passing through it.
By default, traffic to and from the self zone is permitted. This means any zone can reach the router (SSH, SNMP, routing protocols) and the router can reach any zone. This is intentional because breaking management access to your own router would be catastrophic during initial configuration.
To lock down access to the router, you create explicit zone-pairs with the self zone as source or destination:
source OUTSIDE destination selfcontrols who can reach the router from outsidesource self destination OUTSIDEcontrols what the router itself can send outbound
The Three Actions#
ZPF gives you three actions to apply to traffic that matches a policy:
Inspect#
This is the action you will use most often. It configures Stateful Packet Inspection (SPI) for the matched traffic. When you inspect traffic in one direction, return traffic is automatically allowed without needing a reverse policy. It also handles ICMP error messages and multi-channel protocols like FTP where the data channel is negotiated dynamically.
Pass#
Similar to a permit statement in an ACL. It forwards the packet but does not track connection state. This means you need a separate policy in the reverse direction if you want return traffic to flow. In practice, pass is rarely used because inspect handles most scenarios better.
Drop#
Silently discards the packet. You can add the log keyword to generate syslog messages for dropped traffic, which is useful for troubleshooting and security monitoring.
The critical distinction: inspect is stateful and handles return traffic automatically. pass is stateless and requires explicit reverse policies. For almost every real-world scenario, inspect is the correct choice.
ZPF vs. ACL-Based Filtering#
| Feature | ACL-Based | ZPF |
|---|---|---|
| Default behavior | Implicit deny at end of ACL | Default deny all between zones |
| Statefulness | Stateless (unless CBAC added) | Stateful with inspect |
| Return traffic | Must explicitly permit with established keyword | Automatic with inspect |
| Application awareness | Limited to port numbers | Protocol-aware via NBAR integration |
ZPF does not eliminate ACLs. You can still reference ACLs inside class-maps for granular source/destination matching. But the firewall logic itself is no longer built on ACLs.
Configuration: The Five Steps#
ZPF configuration follows a consistent five-step process. This structure is one of its strengths because every ZPF setup follows the same pattern regardless of complexity.
Step 1: Create the Security Zones#
zone security INSIDE
description Internal trusted network
zone security OUTSIDE
description External untrusted network
Zones are just logical containers at this point. They do nothing until interfaces are assigned and zone-pairs are created.
Step 2: Define Traffic Classes (Class-Maps)#
Class-maps identify what traffic the policy will act on. You can match by protocol, ACL, or both.
class-map type inspect match-any INSIDE_PROTOCOLS
match protocol tcp
match protocol udp
match protocol icmp
The match-any keyword means traffic matching any one of the listed protocols will be classified. Use match-all if every condition must be true simultaneously.
You can also reference ACLs for source/destination specificity:
access-list 101 permit ip 10.0.0.0 0.0.0.255 any
class-map type inspect INTERNAL_TRAFFIC
match access-group 101
match protocol tcp
match protocol udp
match protocol icmp
Step 3: Specify Firewall Policies (Policy-Maps)#
Policy-maps tie class-maps to actions. This is where you decide what happens to the classified traffic.
policy-map type inspect INSIDE_TO_OUTSIDE
class type inspect INSIDE_PROTOCOLS
inspect
The policy says: for traffic matching INSIDE_PROTOCOLS, perform stateful inspection. Because we used inspect, return traffic will be automatically permitted.
Step 4: Apply Policies to Zone-Pairs#
Zone-pairs define the direction of traffic flow and attach the policy.
zone-pair security IN_TO_OUT source INSIDE destination OUTSIDE
service-policy type inspect INSIDE_TO_OUTSIDE
This creates a unidirectional policy: traffic from INSIDE to OUTSIDE gets inspected. Return traffic (OUTSIDE to INSIDE) is handled automatically by the inspect action. No reverse zone-pair is needed.
Step 5: Assign Interfaces to Zones#
interface GigabitEthernet0/0/1
zone-member security INSIDE
interface GigabitEthernet0/0/0
zone-member security OUTSIDE
The moment you assign an interface to a zone, the deny-all default kicks in. Only traffic explicitly allowed by zone-pair policies will flow.
Complete Working Configuration#
Here is a full ZPF configuration that allows internal users to reach the internet with stateful inspection:
! Step 1: Create zones
zone security Inside
description Inside network
zone security Outside
description Outside network
! Step 2: Define traffic classes
access-list 101 permit ip 10.0.0.0 0.0.0.255 any
class-map type inspect INTERNAL_TRAFFIC
match access-group 101
match protocol tcp
match protocol udp
match protocol icmp
! Step 3: Define policies
policy-map type inspect InsideToOutside
class INTERNAL_TRAFFIC
inspect
! Step 4: Create zone-pairs
zone-pair security InsideToOutside source Inside destination Outside
service-policy type inspect InsideToOutside
! Step 5: Assign interfaces
interface FastEthernet0/0
zone-member security Inside
interface Serial0/0/0.100 point-to-point
zone-member security Outside
Verification#
After configuration, use these commands to verify everything is working:
show zone security
show zone-pair security
show policy-map type inspect zone-pair sessions
show class-map type inspect
show policy-map type inspect
The show zone security command confirms zone membership:
zone self
Description: System defined zone
zone INSIDE
Description: Internal trusted network
Member Interfaces:
GigabitEthernet0/0/1
zone OUTSIDE
Description: External untrusted network
Member Interfaces:
GigabitEthernet0/0/0
The show policy-map type inspect zone-pair sessions command is the most useful for troubleshooting. It shows active sessions, match counters, and which policies are being hit.
Design Patterns#
Internal + Internet (Basic)#
The most common setup. One zone-pair: INSIDE to OUTSIDE with inspect. Internal users access the internet freely. No inbound connections from outside.
Internal + DMZ + Internet (Three-Zone)#
Three zone-pairs needed:
- INSIDE to OUTSIDE (inspect): Internal users access internet
- INSIDE to DMZ (inspect): Internal users access DMZ servers
- OUTSIDE to DMZ (inspect for HTTP/HTTPS only): External users access public services
No OUTSIDE to INSIDE or DMZ to INSIDE zone-pairs. The DMZ is reachable from both sides but cannot initiate connections to the internal network.
Guest Network#
A conference room or guest Wi-Fi zone:
- GUEST to OUTSIDE (inspect HTTP/HTTPS only): Guests browse the web
- No GUEST to INSIDE zone-pair: Guests cannot reach internal resources
Design Rules to Remember#
- No filtering for traffic within the same zone
- One interface, one zone. No exceptions
- Never mix CBAC and ZPF on the same interface
- An interface in a zone with no zone-pair drops everything
- Only explicitly allowed traffic moves between zones
- Traffic to the self zone is permitted by default
- Zone-pairs are unidirectional. Use inspect for automatic return traffic
Takeaways#
- ZPF replaced CBAC by flipping the default from allow-all to deny-all
- Zones group interfaces by trust level. Policy lives between zones, not on interfaces
- The self zone represents the router itself and permits traffic by default
- Inspect is stateful and handles return traffic. Pass is stateless and requires manual reverse policies
- Configuration follows five consistent steps: zones, class-maps, policy-maps, zone-pairs, interface assignment
- Always verify with
show zone securityandshow policy-map type inspect zone-pair sessions


Comments (0)
Sign in to join the conversation