ACL Placement and NAT Order of Operations on a Branch Router
A branch router performs NAT overload on Gi0/1 (inside, 10.20.30.0/24) to Gi0/0 (outside, 203.0.113.2). The web server 10.20.30.10 is statically mapped to 203.0.113.5. Extended ACL 120 is applied inbound on Gi0/1; ACL 110 is applied inbound on Gi0/0. The security team wants to (1) block outbound traffic from a compromised PC, 10.20.30.44, to a known command-and-control address 198.51.100.9, and (2) stop a hostile internet host, 198.51.100.77, from reaching the published web server. They add deny ip host 10.20.30.44 host 198.51.100.9 to ACL 120 and deny ip host 10.20.30.10 host 198.51.100.77 to ACL 110. The outbound block works; the inbound block does not. Later they replace ACL 110 with a single permit tcp any any established rule, and DNS resolution from inside starts failing intermittently while a scanner still reaches an internal service.
1. Explain the NAT ordering that makes one rule work and the other fail, and rewrite the broken rule correctly.
Read the worked answer
Cisco routers apply the inbound ACL before translating the packet. On the inside interface, ACL 120 sees the original packet: source 10.20.30.44, destination 198.51.100.9. The rule matches and the block works.
On the outside interface, the inbound packet's destination is the inside global address, 203.0.113.5, not 10.20.30.10. Translation to the inside local address happens after that ACL check. The rule deny ip host 10.20.30.10 host 198.51.100.77 therefore never matches, and the packet is permitted by whatever broader rule follows.
Corrected rule: deny ip host 203.0.113.5 host 198.51.100.77, placed before any permit for 443 to the web server. If you also need to protect the mail server, use its global address 203.0.113.4. In general: match inside-local addresses on inside-facing ACLs and inside-global addresses on outside-facing ACLs, and remember that a static NAT does not change this ordering. Verify with show ip access-lists counters after a test connection attempt, and with debug ip nat if the counters do not move.
2. Why is `permit tcp any any established` a poor substitute for a stateful policy, and what broke DNS?
Read the worked answer
The established keyword is stateless. It matches any TCP segment with the ACK or RST bit set, regardless of whether a session ever existed. An attacker can send a packet with ACK set toward any port; it reaches the host, which typically answers with RST, so scanning and some reconnaissance work and any benefit from the rule is not a security boundary. It also provides no protection for UDP or ICMP at all.
DNS broke because it is UDP/53. Return DNS responses are not TCP and are not matched by tcp established; if the outside ACL has no explicit UDP permit for return traffic, replies are dropped and lookups fail intermittently as resolver caches age out. The same is true for return ICMP (PMTUD) and for any UDP-based voice or VPN traffic.
Better approaches: a stateful firewall (zone-based policy firewall on the router, or a dedicated firewall), reflexive ACLs if the platform only supports classic IOS, or a properly scoped inbound ACL that permits only the published services and relies on NAT state for return traffic. Write the policy as: default deny inbound, explicit permits for 443 to 203.0.113.5 and 25/465 to 203.0.113.4, plus ICMP unreachable for PMTUD.
3. The branch has no firewall and the router also terminates SSH for management. Which additional hardening would you insist on before considering the ACL work complete?
Read the worked answer
First, restrict management access: line vty 0 4 with transport input ssh, SSH version 2, and an ACL on the VTY lines permitting only the management subnet 10.20.30.0/24 (or an out-of-band block). Disable ip http server and ip http secure-server unless the automation stack needs them, and if RESTCONF is enabled, scope it to the management VRF with a local or AAA user.
Second, replace local-only authentication with AAA (TACACS+ or RADIUS) and per-user privilege levels or role-based CLI views, so shared enable passwords disappear. Add service password-encryption and, better, type 8/9 secrets.
Third, control the control plane: no ip source-route, no ip directed-broadcast, no ip proxy-arp on the outside, and CoPP or an infrastructure ACL if the platform supports it.
Fourth, fix the underlying architecture: NAT should not be the security boundary. Place a stateful firewall in front of the branch, keep NAT on the firewall, and let the ACLs be a second layer. Logging to syslog and NetFlow to a collector should be in place before the change window so the new denies can be validated.