Anchors For PF Ruleset Management

Posted by Tres Mon, 18 Dec 2006 16:30:00 GMT

Anchors not only provide a way to dynamically change PF rulesets on the fly, they are also a useful technique for organization of larger rulesets. If you’ve ever had to work with anywhere over 500 lines of PF rules, you know it’s manageable, but it’s cumbersome. And if you’ve ever had to share management of a PF ruleset with other administrators, you know that a single pf.conf makes management even more difficult. You also know it’s nearly impossible to manage multiple updates coming from different requesters at the same time with a single file. By breaking down the monolithic pf.conf into separate files, the ruleset is better suited for large numbers of rules and better suited for management by larger organizations with administrators who have varying levels of trust.

In essence, anchors allow you to separate a ruleset among many files, letting you write rules that can be dynamically loaded and unloaded from the firewall. This means you can do things like write a bunch of different rules for different required states, then have them automatically loaded and unloaded by cron. You could write rules that would be activated and deactivated by a junior-admin, or an application. Like all other great *nix tools, the possibilities are limited only by your imagination and need.

Dynamically changing firewall rules may not seem like much at first glance; after all, you can get the same effect from an edit and reload of rules. It’s true, with an edit and reload of rules, there’s no interruption in service, but it does require that a single firewall “manager” make edits to the pf.conf file and then, as root, reload the firewall rules. This process requires special skills and root level trust over the entire ruleset in order to make changes effective. In praxis, anchors provide finer granularity of control over different aspects of the ruleset. This level of granularity opens up a whole new set of tools and utilities that can be created for management and maintenance of the ruleset.

The functional benefits of anchors for a large organization are many, but the ability to organize rulesets into multiple files reduces the overhead involved with managing firewall rules significantly. When deciding how to break down your rules, you should think of rules the same way you would an OOP class; you’re trying to create an abstract encapsulation that will have the ability to act upon every state that the object can have. The fundamental goal here is to break things down into logical pieces that will be manipulable by other administrators. When starting out, you want to make the object types you’re working with as generic and abstract as possible. Each super-class should be used as a directory in which the rule sets will be placed. So if we can define mail_servers as a child of “public_servers,” we would create a directory labeled “public_servers” and put mail_rules into that directory. In turn, if “public_servers” can be a subclass of “servers,” we would create a directory for “servers,” then put “public_servers” as a subdirectory. If you’re using rule groups, these abstract super-classes will not only help in logical organization, they will allow you to define a more abstract set of rules that apply to all sub-classes.

You could logically order rules by interfaces (like vlan128_rules), by physical characteristics (like building_2213_rules), by roles (like student_rules), or by any other characteristic that will make the organization of the rules logical to the group that will manage them. I like to use anchors to break down rules logically by what type of service the rule is for. I also like to categorize the rules into “client” and “server” management groups so things are easier to find, and I don’t make any mistakes about what rules are being edited.

There’s two things that need to happen for an anchor to work. First, PF needs to know where to find the anchor file, and second PF needs to be told to use the anchor file. This may seem kind of redundant at first–and since our primary aim here is to discuss the use of anchors for ruleset management, it will seem redundant–but this separation allows the possibility of loading dynamic rules.

The practical function of an anchor within a pf.conf ruleset is to allow the inclusion of files other than pf.conf for reading into your firewall rules. It’s just like an include in C, or a require statement in Ruby; you’re just telling the server where to look for the definition once it sees it in the firewall. And just like an include or require statement, inclusion of the anchor file into the firewall ruleset doesn’t make anything happen. You’ve got to tell PF to use the anchor–just like calling a function or a class defined in another file.

Below is an example showing use of anchors. One of these files has our rules for allowing access to web servers. The other one has rules that allow access to our mail servers.

Step 1: Including an anchor file from pf.conf This should be near the top of your pf.conf file. I define anchor files after I define queues.

man pf.conf says an anchor should look like this:

load anchor <name> from <file>

So, for our example, we would do something like this:

load anchor mail from /usr/local/etc/pf_anchors/servers/mail_rules
load anchor http from /usr/local/etc/pf_anchors/servers/web_rules

Step 2: Telling PF to use the included anchor Telling PF to use the anchor means putting a reference to the anchor in the relevant section of pf.conf. That means nat-anchor directives should go into the NAT section of the ruleset, rdr-anchor directives go into the RDR section and anchor directives go with all the other filter rules.

nat-anchor mail
nat-anchor web


rdr-anchor mail
rdr-anchor web


anchor mail
anchor web

These represent three different sections of your pf.conf. You should make sure that any NAT, RDR or filter rules are placed into pf.conf appropriately. If you don’t PF will let you know it.

Posted in , ,  | Tags , , ,