{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Provably safe ACL and firewall rule changes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Changing ACLs or firewall rules is one of the riskiest updates to a network. Even a small error can block connectivity for a large set of critical services or open up sensitive resources to the world at large. \n", "\n", "This notebook shows a 3-step process that uses Batfish to make provably safe and correct changes to ACLs and firewall rules, which we generally call filters. For a broader view of Batfish's support for analyzing filters, check out the [\"Analyzing ACLs and Firewall Rules\" notebook](https://github.com/batfish/pybatfish/blob/master/jupyter_notebooks/Analyzing%20ACLs%20and%20Firewall%20Rules.ipynb).\n", "\n", "Check out a video demo of this notebook [here](https://www.youtube.com/watch?v=MJYLVL9UOWk).\n", "\n", "We will primarily use the `searchFilters` question of Batfish in this process. This question searches within large spaces of flows (specified using packet headers) for flows that match the specified action ('permit' or 'deny'). See [here](https://pybatfish.readthedocs.io/en/latest/notebooks/filters.html#Search-Filters) for its documentation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Change scenario" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our goal is to update an ACL on one of our routers to permit HTTP traffic (ports 80 and 8080) from one subnet (10.10.10.0/24) to another (18.18.18.0/27). We will implement this by adding rules to permit this traffic to our ACLs, and we will then use Batfish to check if the implementation was correct." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start by initializing the pre-change snapshot and variables that describe the change. Our example snapshot contains two devices, and we'll change the ACL **acl_in** on [**rtr-with-acl**](https://github.com/batfish/pybatfish/blob/master/jupyter_notebooks/networks/example-filters/current/configs/rtr-with-acl.cfg). " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'current'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Import packages\n", "%run startup.py \n", "bf = Session(host=\"localhost\")\n", "\n", "# Initialize a network and snapshot\n", "CURRENT_SNAPSHOT_NAME = \"current\"\n", "CURRENT_SNAPSHOT_PATH = \"networks/example-filters/current\"\n", "bf.set_network(\"network-example-filters\")\n", "bf.init_snapshot(CURRENT_SNAPSHOT_PATH, name=CURRENT_SNAPSHOT_NAME, overwrite=True)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "node_name = \"rtr-with-acl\" # The router to change\n", "filter_name = \"acl_in\" # Name of the ACL to change\n", "\n", "# The traffic to allow\n", "change_traffic = HeaderConstraints(srcIps=\"10.10.10.0/24\",\n", " dstIps=\"18.18.18.0/27\",\n", " ipProtocols=[\"tcp\"],\n", " dstPorts=\"80, 8080\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 1: Ensure that the intended traffic is not already permitted" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before we make the change to allow the intended traffic, we verify that that traffic is not already permitted — because if it is, we do not need to change anything. We accomplish this using the `searchFilters` question. Given a space of flows, specified using header fields such as source and destination addresses and ports, and a matching condition (e.g., permit, deny) as input, this question finds flows that satisfy the condition. If it reports no flows, then it is guaranteed that no flow within the space satisfies the condition. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "KeyPresence | \n", "Snapshot_Action | \n", "Reference_Action | \n", "Snapshot_Line_Content | \n", "Reference_Line_Content | \n", "Snapshot_Trace | \n", "Reference_Trace | \n", "
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | \n", "rtr-with-acl | \n", "acl_in | \n", "Start Location: rtr-with-acl Src IP: 10.10.10.0 Src Port: 49152 Dst IP: 18.18.18.32 Dst Port: 80 IP Protocol: TCP (SYN) | \n",
" In both | \n", "PERMIT | \n", "DENY | \n", "462 permit tcp 10.10.10.0/24 18.18.18.0/26 eq 80 | \n", "2020 deny tcp any any | \n", "
| \n",
"
| \n",
"
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "Action | \n", "Line_Content | \n", "Trace | \n", "
|---|
| \n", " | Node | \n", "Filter_Name | \n", "Flow | \n", "KeyPresence | \n", "Snapshot_Action | \n", "Reference_Action | \n", "Snapshot_Line_Content | \n", "Reference_Line_Content | \n", "Snapshot_Trace | \n", "Reference_Trace | \n", "
|---|