Keeping track of changes with cfengine and SubVersioN

Cfengine is a tool which purpose is to describe what is a healthy system and how to bring it back to normal when something fails.

I won’t go into an explanation about how cfengine works, because the project webpage already has a neat tutorial and complete reference. Instead of that, I’ll explain how I used cfengine to build a fool proof Linux firewall.

Considerations

The firewall itself is a basic out-of-the-box Debian system, the firewalling part being setup by an shell script /etc/init.d/iptables which in turn is linked in /etc/network/if-up.d to ensure it runs when network comes up.

As this simple script will hold all the rules, it is expected to evolve with time. I wanted changes in the rule set as well as changes in the main configuration files of the firewall to be properly logged to know who changed something, when, and why.

This is why I decided to put all those precious files in a SubVersioN repository (by the way, SubVersioN — SVN for short — is a great version control system and I recommend reading this book to get most out of it).

But you know how are people ? If you let them do they’ll just go log into the firewall box, and change the rules and config files without bothering documenting what they changed.

With the help of cfengine … No more !

Outline

The idea of it all is that all the configuration (including the iptables ruleset) will be stored in an SVN repository.

Changes will be made on a test machine. When they’ll be considered OK they’ll be commited back into the repository. A log will be filled, and will keep track of which change, when and who did it.
The firewall keeps an updated working copy of the repository, and this one is used as a reference.

When the production config files differ from the reference, cfengine spots replaces them with the reference ones.

The consequence is that if someone modifies, say, /etc/init.d/iptables then after a short while that file will be overwritten by the reference file.

Implementation

A cron job updates the SVN working copy of the reference config files with something along a simple “svn update”.

Another cron job then runs cfexec -F. This one is responsible of running cfagent, which in turn is responsible for returning config files to the “normal” state, that is to say equal to the reference ones.

This is done with a set of rules such as :

copy:
$(REFERENCE)/etc/init.d/iptables
dest=/etc/init.d/iptables
owner=root group=root
mode=0700
type=checksum

This merely means to copy files from the reference store if they differ (based on the md5 checksum) with appropriate permissions.

Conclusion

With such a simple design and great tools, you can ensure that modifications will be consistently logged not because everyone knows it’s important, but because there’s no choice (or to be more specific : because bypassing the correct process is more complicated than complying :-D)