- -Manually reasoning about what an ACL or firewall policy will do to a packet, when it has rules that cover - multiple fields of the IP header, is extremely difficult and as the rules grow in size becomes virtually - impossible. Add to that the task of understanding what a change to the ACL or firewall policy will do, - and you are in for quite a ride. - -This is where a tool such as Batfish comes into play. It provides multiple methods of analyzing ACLs and - firewall rules, so that you can ensure that your security policy functions as desired. And it is built for - you to do this programmatically, so you can easily incorporate this into any workflow. - -Batfish provides 4 core capabilities for Firewall and ACL audit and analysis:. -


-
    -
  • testFilters
  • -
  • searchFilters
  • -
  • filterLineReachability
  • -
  • compareFilters
  • -
-


-This article will show you how to use each of these capabilities to audit/analyze an ACL of firewall policy. - So let’s get started. This article assumes some familiarity with Batfish. - Please view the GitHub page - and docs page for an overview. -

Analyzing the Firewall/ACL behavior for a specific flow

-Note: A detailed Jupyter notebook covering this example can be found - here -


- - -The testFilters query allows you to analyze the behavior of a filter - (Firewall policy or ACL rule) with respect to a specific flow. For example, if I want to determine if an ACL - is allowing a specific host to reach the - DNS server, I would use testFilters as shown below. -


- - - - - - -
-# Check if a representative host can reach the DNS server -
-dns_flow = HeaderConstraints(srcIps="10.10.10.1", dstIps="218.8.104.58", - applications=["dns"]) -


-answer = bfq.testFilters(headers=dns_flow, nodes="rtr-with-acl", - filters="acl_in").answer() -


-show(answer.frame()) -
-


- - - - - - - - - - - - - - - - - - - - - - -
NodeFilter nameFlowActionLine contentTrace
rtr-with-aclacl_inStart Location: rtr-with-acl - -Src IP: 10.10.10.1 - -Src Port: 49152 - -Dst IP: 218.8.104.58 - -Dst Port: 53 - -IP Protocol: UDPPERMIT660 permit udp 10.10.10.0/24 218.8.104.58/32 eq domainMatched line 660 permit udp 10.10.10.0/24 218.8.104.58/32 eq domain
-


- -With a simple query, you can get a definitive answer about the behavior of a filter with regards to a specific flow. - So before you make a change to an ACL or firewall rule, you can test the existing one and determine what action - it takes for a specific flow (or sets of flows). - -But if you wanted to analyze the behavior of a Firewall or ACL for a large set of flows, you would use - searchFilters instead. -

Analyzing the Firewall/ACL behavior for a large set of flows

-Note: A detailed Jupyter notebook covering this example can be found -here -


- -Building on the previous example, let’s see if the ACL permits access to the DNS server for ALL hosts in a given subnet. - To do that, you actually “search” for any DNS flow from the source subnet to the DNS server that is denied. - You are asking Batfish to see if there are any flows that violate your policy that all hosts in the given - subnet MUST have access to the DNS server. -


- - - - - - -
-# Check if the subnet can reach the DNS server -


-dns_traffic = HeaderConstraints(srcIps="10.10.10.0/24", dstIps="218.8.104.58", applications=["dns"]) -


-answer = bfq.searchFilters(headers=dns_traffic, action"deny", filters="acl_in").answer() -


-show(answer.frame()) -
-


- - - - - - - - - - - - - - - - - - - - - -
NodeFilter nameFlowActionLine contentTrace
rtr-with-aclacl_inStart Location: rtr-with-acl - -Src IP: 10.10.10.42 - -Src Port: 49152 - -Dst IP: 218.8.104.58 - -Dst Port: 53 - -IP Protocol: UDPDENY460 deny udp 10.10.10.42/32 218.8.104.58/32 eq domainMatched line 460 deny udp 10.10.10.42/32 218.8.104.58/32 eq domain
-


- -As you can see, we did get a flow that matches the search condition and thus violates our desired guarantee of the - entire subnet being able to reach the DNS server. The columns carry the same information as those for - testFilters and provide insight - into the violation. In particular, we see that a flow with source IP 10.10.10.42 is denied by an earlier line - in the ACL. Such needles in the haystack are impossible to find with other tools and techniques. - -Both testFilters and - searchFilters help you analyze - the behavior of an ACL or firewall rule with regards to a given flow or sets of flows. But Batfish provides - another interesting capability to analyze a filter - - filterLineReachability. -

Identifying unreachable filter lines

-Note: A detailed Jupyter notebook covering this example can be found here -


- -What once started out as a nice pristine and easy to understand ACL or firewall policy, over time turns into quite a - mess as the network and services evolve. Oftentimes, you end up creating new rules that are partially or fully - masked by earlier rules, thereby rendering your changes partially and wholly ineffective. - To help you in this situation, Batfish has the query - filterLineReachability. -


- - - - - - -
-# Find unreachable lines in filters of rtr-with-acl


-aclAns = bfq.filterLineReachability(nodes="rtr-with-acl").answer() -


-show(aclAns.frame()) -
-


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SourcesUnreachable lineUnreachable line actionBlocking linesDifferent actionReasonAdditional info
rtr-with-acl: acl_in670 permit ip 166.146.58.184 anyPERMIT540 deny ip 166.144.0.0/12 anyTrueBLOCKING_LINESNone
rtr-with-acl: acl_in790 deny ip 54.203.159.1/32 anyDENY500 deny ip 54.0.0.0/8 anyFalseBLOCKING_LINESNone
-


-Each line in the answer above identifies an unreachable line in a firewall policy or ACL. Let’s take a closer look at the first one. - It shows that the line 670 permit ip 166.146.58.184 any is unreachable because it is blocked by the - line 540 shown in the Blocking_Lines column. The Different_Action column - indicates that the blocking line 540 has the opposite action as the blocked line 670, - a more worrisome situation than if actions were the same. -The Reason column shows that the line is unreachable because it has other lines that block it, - Lines can also be independently unreachable (i.e., no packet will ever match it) or may be unreachable - because of circular references. - The filterLineReachability - question identifies such cases as well, and provides more information about them in the Additional_Info - column. - -


-

Comparing the behavior of Firewall policies or ACLs

-Note: A detailed Jupyter notebook covering this example can be found here -


- -As your network evolves, the ACL and firewall policies change and grow, often resulting in large rule-sets that can - exceed the capability of the specific device it is applied to, or result in a performance degradation. - So you periodically try to refactor / compress these rules to mitigate this problem. - The compareFilters query in - Batfish allows you to compare the behaviors of your existing ACL/firewall policy and the new compressed one to - ensure that you are not permitting or denying more traffic than desired. - -

-
- - - - - - -
-

-#original_snapshot - original_snapshot="original" -


-

#compressed_snapshot - compressed_snapshot="compressed" -


-# Now, compare the two ACLs in the two snapshots - -answer = bfq.compareFilters().answer(snapshot=compressed_snapshot, reference_snapshot=original_snapshot) -show(answer.frame())
-
-


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NodeFilter nameLine indexLine contentLine actionReference line indexReference line content
configacl16210 deny ip 218.67.71.0/23 anyDENY50510 permit icmp any any echo-reply
configacl40510 permit icmp any any echo-replyPERMIT21220 deny ip 218.67.72.0/24 any
configacl41880 deny ip any anyDENY780 permit tcp 205.248.58.190/32 205.248.58.188/32 eq bgp
-


-The compareFilters question - compares two filters (firewall policies or ACLs) and returns pairs of lines, one from each filter, that match - the same flow(s) but treat them differently. If it reports no output, the filters are guaranteed to be identical. - The analysis is exhaustive and considers all possible flows. - -As we can see from the output above, our compressed ACL is not the same as the original one. - In particular, line 210 of the compressed ACL will deny some flows that were being permitted by - line 510 of the original; and line 510 of the compressed ACL will permit some flows - that were being denied by line 220 of the original ACL. Because the permit statements correspond - to ICMP traffic, we can tell that the traffic treated by the two filters is ICMP. To narrow things down to - specific source and destination IPs that are impacted, you can run the - searchFilters query. - -To see these queries in action on example networks, please check out the Jupyter notebooks - here. - Also, don’t forget to check out our video tutorials. -

Community created resources

-A number of members of the Batfish open-source community have created content related to ACL and firewall policy - changes. You can find a few of them here: -


- - -

Summary

-Analyzing firewall poliices and ACLs is a pretty complex task. Batfish has a number of core - capabilities that greatly simplifies this, as shown above. - Batfish Enterprise - (offered by Intentionet) builds on these capabilities and provides - an interactive UI-based and programmatic workflow to make it even easier to use. To learn more about - Batfish Enterprise, follow this - link. - -If you want to learn more about Batfish or get involved in the open-source community, please join our - Slack - workspace or find us on GitHub. -