I took over administrative duties for an Linux environment of around 20 boxes. Trying to consolidate configuration management with Puppet. Most is straightforward, however I stumbled on the firewall rules.

Previous administrator relied on a custom script that created iptables rules for each box out of a common template.

The template rules look like this:

hostname:   Action   Interface   Source    Protocol   destPort

Some examples:

ALL:          Accept   eth0    any           tcp   80
server4:       Accept   All    x.x.x.x/24   tcp/udp   111
node5:         Deny     All    y.y.y.y

Rules for ALL would apply to all boxes. The rest of the params are used to populate iptables rules. There are about 250 rules in the template.

Is it possible to re-use this common template via puppet and build iptables ruleset for each node? Is this kind of text mangling even possible with puppet?

  • 1
    This isn't really an answer for your specific question, but it's worth adding to the discussion: Puppet is best used when the templates aren't your source of data. Instead, use Hiera (docs.puppetlabs.com/hiera/1/hierarchy.html) to set these rules in your hierarchy and have a template in a module implement them. The puppetlabs/firewall module + hiera and create_resource() would get what you are trying to accomplish done in a much cleaner way. Let me know if you want more details and I'll add this as an answer. – Dan Bowling Sep 1 '15 at 21:18
up vote 4 down vote accepted

Not really.

To be more exact; it's technically possible. But since neither puppet's DSL or puppet itself is designed for such tasks¹, you'll accrue technical debt on a brittle gum-and-paperclip solution.³

IMHO, since you want to keep this template, the best course of action is to write a script which will transform data from this apparently legacy format into to the native puppet DSL (emitting .pp files you'll include appropriately)², using whatever Types/Modules that are most fitting to your boxen.

Now instead of re-running the script all the time, I would make your puppet manifests the authoritative source instead. I.e. do all changes in there, and export as necessary, until you got rid of the legacy plumbing that relies on this format. It may make sense to omit this if your transition period is short enough; and you don't mind 'importing' a few times.

¹) That should be obvious if you think briefly about it: A CM's duty is to be the authoritative source of configuration data, not to mangle data. That's what sed, awk, Pipes, et al. are for.

²) Consider hiera as well.

³) Most likely, your successor will hate your for it, and more importantly, you'll hate yourself after some distance down the rabbit hole.

  • 1
    Your footnotes are cute. – Joseph Kern Sep 4 '15 at 8:52
  • After some time I can only imagine using File resource with an Exec. The exec resource would be a script that mangles the "template" into an iptables rules. In fact I already have this script that mangle that template into machine-specific rule-set. How do I capture it's output with Puppet to create the ruleset file? Naturally I'd want Puppet to re-run this script whenever the input template changes. – Swartz Sep 5 '15 at 7:56
  • Something like exec { "create_ruleset": command => "/bin/processor /path/to/template_file" } Would this work? Now need to keep track of changes to two files: template to re-excute and ruleset if manually changed somehow? Is this doable? – Swartz Sep 5 '15 at 8:00
  • No, you don't. IMHO, the better/correct way would be to put the legacy template file on the node with a File resource, and then notify the exec resource. It is then up to your processor script to 1. generate the ruleset 2. load the ruleset. Anything else would load up your manifests with a kind of logic they're not meant for, described in my answer. Also leave a #TODO note to your future self to get rid of this and use a native resource to manage iptables as soon as you can. – Roman Sep 7 '15 at 14:26
  • This made sense. I got it working (i think). Doing further testing. – Swartz Sep 8 '15 at 7:59

The sanest way of doing this would be parsing your old config from the legacy files you mentioned into puppet DSL with a custom script and modifying the firewall module to include support for your legacy systems and run puppet on them too.

You could use the ipfilter on the puppet forge as a starting point.

A quick and dirty way to do this would be by using define to wrap ipfilter and firewall depending on the node's operating system.

It kinda looks like someone wanted to reimplement shorewall and didn't quite get there...

I think you're going to out of luck looking for a ready-made solution which will turn that custom file format into Puppet resources; being a custom file format, nobody else will have ever heard of it or dealt with it. The format looks relatively straightforward, though, so a quick bit of scripting in a language of your choice should make it possible to turn it into resources. The next question, of course, is which package to use to define the firewall resources within Puppet...

If, instead, you're looking to keep the crazy custom file format, but use Puppet as an intermediary to ship the "compiled" rulesets out to machines, I'd advise against doing anything particularly fancy. I'd probably look to "compile" the rulesets on the Puppetmaster when you deploy the tree, so that if there are changes to the "source" file, new rulesets will then be available in the fileserver to be shipped out to the clients when they next run.

  • 1
    There is some legacy stuff (like solaris9) that uses this. This thing was good enough back when it was written, but time moves on. I'd prefer to use this template as base. Otherwise I have to convert it, and maintaining two lists (this template and puppet-specific template). – Swartz Aug 24 '15 at 5:17
  • For the record, I'm ok with writing something from scratch. Just wanted to find out if something like this is even possible with Puppet. – Swartz Aug 24 '15 at 5:20
  • To answer your question, yes I'd prefer keep this template as input and use Puppet to convert it to an iptables ruleset for appropriate machines. Don't need anything fancy. Template goes in, rulesets go out for right machine. Is this even viable with Puppet? – Swartz Aug 24 '15 at 5:31
  • Yes, I described how to do that in my answer. – womble Aug 24 '15 at 5:39

I disbelieve that you can implement this kind of transformation inside the Puppet DSL.

You will want to write a Ruby function that consumes the text input and creates resources for the firewall module.

We are using Shorewall to achieve this. Shorewall builds upon iptables (netfilter). There are several modules in the puppetlabs to automate Shorewall in Puppet.

Usually you have a couple of data sources in Puppet, for example Hiera and an ENC. In this case, if you have set-up Hiera the right way, you can have your firewall configuration in there. The good thing with Hiera is that you can "overrule" configuration for specific networks/hosts/services/etc (for example: default.yaml -> webserver.yaml -> apache.yaml). The most specific containing the key you need will be leading.

If you need to get rules from a database (MySQL for example) you can have the ENC pass those to Puppet.

In Puppet you can make templates for Shorewall (ex: webserver.erb) and include them in your shorewall configuration. They could contain something like:

# This file is managed by Puppet
<% @firewall_rules.each do |entry| -%>
<%= entry['ip'] %>/<%= entry['mask'] %> - - src,dst
<% end -%>

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.