Now I can say, from experience, that in my opinion one of the most frustrating admin tasks can be ACL updates on multi-tier firewall environments. Validation of the change and any troubleshooting if an ACL is still missed can be tedious and lengthy.
Therefore, I'm delighted today to bring you this 3 part series - A Hands-on Guide to Multi-Tiered Firewall Changes with Ansible and Batfish.
This guide is an introduction/beginner’s guide to both Ansible and Batfish, and how to validate your firewall changes using these tools. The steps and workflow have been written in a way that DO NOT require any fancy automation stacks, CICD pipelines or gitops foo.
What are we waiting for? Let’s go...
Note: The code for this guide can be found within the following repo: https://github.com/rickdonato/batfish-ansible-dual-tier-fw-demo
What is Batfish?
Batfish is an open-source network configuration analysis tool that provides the ability to validate configuration data, query network adjacencies, verify firewall ACL rule sets and also analyze routing/flow paths.
In other words (https://www.batfish.org/),
Batfish finds errors and guarantees the correctness of planned or current network configurations. It enables safe and rapid network evolution, without the fear of outages or security breaches.
Network configurations are packaged and fed to Batfish via snapshots. A snapshot being a collection of information (configuration files, routing data, up/down status of nodes and links) that represent the state of the network. Therefore, Batfish does NOT require direct access to network devices. The required layout of a snapshot is based on the following key folders:
- configs/ - network device configuration files.
- hosts/ - host configuration files.
- iptables/ - host iptable configuration files.
Further information can be provided to Batfish, see here. However, for the context of this article, our snapshot will consist of the above.
Batfish runs as a containerized service, from the data supplied via the snapshot, Batfish builds a series of models which are then queried either using the python SDK - pybatfish or the Batfish Ansible role. By being able to query a set of central models we can perform some extremely useful queries, such as on flows, which we will show later.
What is Ansible?
Ansible is open-source software that automates software provisioning, configuration management, and application deployment, based upon an agentless architecture. Hosts are managed by an Ansible control machine via SSH.
Over the years Ansible has become extremely popular in the world of network automation. This is down to Ansible’s,
- easy to use DSL to define the intended actions.
- low level of entry (programming experience required). Though it can help when you move onto more advanced areas of Ansible.
- strong community.
- vast collection of multi-vendor network modules.
Ansible consists of a number of components. Below details the main ones:
- Controller Machine: This is where Ansible is installed and from where the hosts and managed via SSH.
- Inventory: Contains each of the hosts that are to be managed.
- Playbook: Simple files written in YAML that describe actions that we want to be performed. These actions are constructed based on the following hierarchy:
- Play: Contains a set of tasks.
- Task: Contains a set of modules.
- Module: Modules control system resources, like services, packages, files, or execute system commands. Or in other words, perform the required action/actions.
Figure 1 - Ansible Key Components.
Our installation will consist of the following:
- Installing Batfish via a Docker container.
- Installing Ansible (with the Ansible Batfish role) within a Python virtual environment.
Once our installation is complete our setup will look like the below:
Figure 2 - Example Setup.
To install Batfish the following commands are run to pull down and then run our Batfish container image.
docker pull batfish/allinone docker run --name batfish -d -v batfish-data:/data -p 8888:8888 -p 9997:9997 -p 9996:9996 batfish/allinone
In addition to the API, the Batfish service also provides a set of Jupyter notebooks. This gives you a set of pre-baked how-to guides and scenarios so you can start kicking the tyres with minimal fuss. Also, as they are provided as Jupyter notebooks, you get additional benefits such as being able to interact with Python inline via the browser. To access this go to
<your_ip>:8888. You will be asked for a token, which you can get from running the command
docker logs batfish.
Figure 3 - Batfish Jupyter Notebooks.
The installation of Ansible will consist of creating a Python virtual environment and then performing
pip install … to install Ansible and the various dependency packages.Once done the Batfish role is installed.
To help you with the steps above I have put together a small Makefile. Therefore, the only commands that you will need to run are:
git clone https://github.com/rickdonato/batfish-ansible-dual-tier-fw-demo cd batfish-ansible-dual-tier-fw-demo make add-venv-py3.6
Note: For those of you who haven't used Makefiles before they simply allow us to bundle a number of shell commands together and run them via a single make statement. If you want to learn more, feel free to either perform a
cat Makefile to see the contents or for a more detailed description of Makefile click here.
Next, we install the Ansible Batfish role, like so,
ansible-galaxy install --force batfish.base
This will provide us with the following Ansible modules,
- bf_session - Setup the connection to the server running Batfish or Batfish Enterprise.
- bf_init_snapshot - Initialize a network snapshot.
- bf_set_snapshot - Set the current Batfish network and snapshot.
- bf_extract_facts - Retrieve configuration facts for devices in the snapshot.
- bf_validate_facts - Validate configuration facts for devices in the snapshot.
- bf_assert - Validate network behaviour.
- bf_upload_diagnostics - Upload anonymized diagnostic information about a Batfish snapshot.
To validate that everything is installed as expected the following commands can be run:
$ source venv/bin/activate $ pip freeze | grep -i "ansible==2.9.0" ansible==2.9.0 $ ansible-galaxy list # /root/.ansible/roles - batfish.base, master
As part of the code repo that you will have just cloned you will now have the following playbooks. We will be going through each of these later
# ls -l ansible/playbooks/ total 24 -rw-r--r-- 1 root root 937 Dec 6 10:35 bf_gather_validate_facts.yml -rw-r--r-- 1 root root 592 Dec 5 15:09 bf_init_snapshot.yml -rw-r--r-- 1 root root 2645 Dec 9 09:31 bf_validate_acls_flows.yml -rw-r--r-- 1 root root 1031 Dec 5 15:27 bf_validate_snapshot.yml -rwxr-xr-x 1 root root 2646 Dec 6 14:49 create_bf_snapshot.yml -rw-r--r-- 1 root root 630 Dec 9 12:53 push_config.yml
In the next part of this 3 part series we will be looking at an example topology and also dive into the different Ansible Modules that the Batfish role provides. See you there...