Skip to content

The Chef Firewall Cookbook: a Leaky Abstraction

Managing a firewall is hard. Designing an abstraction layer on top of a firewall is even harder. Not only do you need to understand networking and your operating system, but you need to figure out a way to map common operations on firewalls to specific implementation rules. And you’ll need a way to manage firewalls across a fleet of machines. If this sales pitch hasn’t encouraged you to buy a hardware firewall yet… enter the Chef Firewall cookbook.

Leaky Abstractions

The firewall networking world is filled with leaky abstractions. iptables, ufw, firewalld, and shorewall are all abstractions on top of the netfilter framework. Windows Sockets is a wrapper for Berkley Sockets, with a few quirks introduced. Every time we place an abstraction layer on a component, there’s an opportunity for it to leak. It’s no wonder that so many systems administrators turn to Google for writing firewall rules.

All non-trivial abstractions, to some degree, are leaky.
Joel Spolsky

One of my favorite examples of a leaky abstraction in Chef is the package resource and family of providers. For example, you can normally use the package resource to install a package from a local file (e.g. package '/root/foo.rpm'). But, if you’re on a Debian-based system, you have to do something slightly different (e.g. dpkg_package '/root/foo.deb') due to the provider for ‘package’ being Apt-based, not Dpkg-based.

The Many Chef Firewall Cookbooks

In the Chef community, there’s often, “more than one way to do it.” If you only need to support one firewall, and dependencies don’t matter, then you should pick the firewall cookbook that best meets your needs; e.g. for iptables-based work, check out iptables, iptables-ng, iptables_web, chef-iptables, easy-iptables, confd-iptables, diptables, simple-iptables, simple-iptables-ng,.

If you just need to get stuff done, and have relatively simple requirements, then we built the Chef Firewall cookbook for you. We designed this cookbook to provide abstraction over iptables, ufw, firewalld, and the Windows Firewall (!). Due to the goal of addressing the most common needs, and trying to wrap so many different firewall software packages, we’ve definitely built some leaky abstractions.

Dragons encountered when building this cookbook

Here are some considerations when building a cookbook with deceptively simple resources like firewall and firewall_rule.

  • Iptables has package names, service names, and configuration files that can vary across distros, and may or may not separate out IPv6 functionality into a separate package/service/config file.
  • Iptables syntax actually varies a bit across versions of Ubuntu a bit, to the point where comments aren’t supported in the older implementation.
  • Firewalld has concepts like ‘service’ and ‘port’, as well as ‘direct rules’ we could use (see this link).
  • Ufw doesn’t allow you to inject state using configuration files; its state is in a binary file we can’t change easily with Chef.
  • Ufw has some inbuilt rules that it will always load before and after user-specified rules, and packages can modify these.
  • Disabling the firewall vs. stopping it can mean something different on Windows. Doing the wrong thing can disconnect you from an instance, even with stateful rules.
  • Parsing firewall rules is very difficult, given the lack of documented syntax for each system.
  • Different tables are supported by iptables (prerouting, postrouting, filter, etc) that don’t map to a concept on other firewalls.

Despite the list above, I think we’re still better off than trying to produce tens of cookbooks for each possible firewall technology. Leaky abstractions aside, users of the firewall cookbook can use it to:

  • quickly disable or enable the firewall
  • have a shared interface for adding additional rules in dependencies
  • implement most simple rules like filtering traffic using an IP address or port number
  • use iptables on systems that default to firewalld or ufw

And where possible, we’ve tried to design a release-valve where you can put in raw rules or specify custom arguments to commands, to allow power users to get around our leaky abstractions.

Contributors welcome!

Published inTechnology