How to work around lack of array support in puppetlabs-firewall?

After a couple of irritating firewalling oversights I decided to have a go at replacing my hacked-together firewall management scripts with the puppetlabs-firewall module.

It’s going okay, but one thing I’ve found quite irritating is the lack of support for arrays of things such as source IPs or ICMP types.

For example, let’s say I have a sequence of shell commands like this:

readonly IPT=/sbin/iptables
for icmptype in redirect router-advertisement router-solicitation \
                address-mask-request address-mask-reply; do
    $IPT -A INPUT -p icmp --icmp-type ${icmptype} -j DROP

You’d think that with puppetlabs-firewall you could do this:

class bffirewall::prev4 {
    Firewall { require => undef, }
    firewall { '00002 Disallow possibly harmful ICMP':
        proto    => 'icmp',
        icmp     => [ 'redirect', 'router-advertisement',
                      'router-solicitation', 'address-mask-request',
                      'address-mask-reply' ],
        action   => 'drop',
        provider => 'iptables',

Well it is correct syntax which installs fine on the client, but taking a closer look it hasn’t worked. It’s just applied the first firewall rule out of the array, i.e.:

iptables -A INPUT -p icmp --icmp-type redirect -j DROP

There’s already a bug in Puppet’s JIRA about this.

Similarly, what if you need to add a similar rule for each of a set of source hosts? For example:

readonly MONITORS=""
readonly CACTI=""
readonly ENTROPY=""
# Allow access from:
# - monitoring hosts
# - cacti
# - the entropy VIP
for host in ${MONITORS} ${CACTI} ${ENTROPY}; do
    $IPT -A INPUT -p tcp --dport 8888 -s ${host} -j ACCEPT

Again, your assumption about what would work…

    firewall { '08888 Allow egd connections':
        proto    => 'tcp',
        dport    => '8888',
        source   => [ '', '', '',
                      '', '' ],
        action   => 'accept',
        provider => 'iptables',

…just results in the inclusion of a rule for only the first source host, with the rest being silently discarded.

This one seems to have an existing bug too; though it has a status of closed/fixed it certainly isn’t working in the most recent release. Maybe I need to be using the head of the repository for that one.

So, what to do?

Duplicating the firewall {} blocks is one option that’s always going to work as a last resort.

Puppet’s DSL doesn’t support any kind of iteration as far as I’m aware, though it will in future — no surprise, as iteration and looping is kind of a glaring omission.

Until then, does anyone know any tricks to cut down on the repetition here?

7 Responses to “How to work around lack of array support in puppetlabs-firewall?”

  1. Dominic Cleal Says:

    The usual way to do iteration at the moment (when not using the future parser/evaluator) is a defined type, e.g.

    define firewall_egd() {
    firewall { “08888 Allow egd connections from ${title}”:
    proto => ‘tcp’,
    dport => ‘8888’,
    source => $title,
    action => ‘accept’,
    provider => ‘iptables’,
    firewall_egd { [‘’, ‘’, ‘’,
    ‘’, ‘’]: }

    This works because you can declare resources using an array as the title, which creates an instance of that resource per item in the array. By using $title inside the define, you can then get the “variable” within the “loop”. This only works effectively for a single variable, else you start needing hashes or to split strings.

    Side note, avoid using resource defaults (as in your first DSL example), they’re leaky due to dynamic scopes and can introduce surprises when you include other classes.

  2. Andy Says:

    Thanks Dominic, I’ll give that a try!

  3. sk Says:

    Thanks, a lot !
    you saved me some serious headaches

  4. Alex Harvey Says:

    Hi there,

    For anyone else interested, I have provided a Forge module to solve this problem:

  5. Building a highly available ELK solution with Puppet, Part II: Elasticsearch backend | Razor Consulting Says:

    […] have expected that the puppetlabs/firewall type would accept arrays of source addresses, e.g. here, here, […]

  6. Building a highly available ELK solution with Puppet, Part II: The base profile | Razor Consulting Says:

    […] have expected that the puppetlabs/firewall type would accept arrays of source addresses, e.g. here, here.  This might seem like a limitation of the module, although a firewall resource is a representation […]

  7. Legooolas Says:

    [Replying to a very old post, I know, but this problem still exists in the puppetlabs-firewall module, although workarounds have got a bit neater 🙂 ]

    The iteration functions allow expanding this sort of thing in a neater way:

    each($subnets) |$subnet| {
    # Expand subnets array into multiple rules
    firewall { “100 snat for internal network ${subnet}”:
    chain => ‘POSTROUTING’,
    jump => ‘MASQUERADE’,
    proto => ‘all’,
    outiface => $external,
    # Only allow particular source subnets if specified:
    source => $subnet,
    table => ‘nat’,

    Better than having to make a define.

Leave a Reply