Thursday, November 7, 2013

Using puppetlabs/firewall to manage iptables on Linux servers.

A while back, I rolled my own Puppet module to manage the iptables/ip6tables rules on all my servers at work.  This worked OK for a while, but now I am getting tired of debugging each little issue that pops up.

Puppetlabs has their own firewall management module now.


Here is my new configuration using their module.   Looking for a bit of feedback on this design before I pull the trigger, rip out mine, and roll with this new system.

First, install their module:
puppet module install puppetlabs/firewall

 I created my own module to support our unique environment:
cd ~
sudo puppet module generate duxklr-wufirewall
sudo mv duxklr-wufirewall /etc/puppet/modules/wufirewall


Initialize the firewall module...

/etc/puppet/modules/wufirewall/manifests/init.pp:
class wufirewall {
  resources { "firewall":
    purge => true
  }
  Firewall {
    before  => Class['wufirewall::postv4', 'wufirewall::postv6'],
    require => Class['wufirewall::prev4', 'wufirewall::prev6'],
  }
  class { ['wufirewall::prev4', 'wufirewall::postv4']: }
  class { ['wufirewall::prev6', 'wufirewall::postv6']: }
  class { 'firewall': }
}


The next set of modules, is the pre/post rules for ipv4/ipv6.   I had these mixed originally and used [] to specify ['iptables', 'ip6tables'], but that started failing on all the CentOS servers I was testing on.   Splitting ip4 and ip6 rules into different classes fixed the issue.   Need to look more into this, keeping them together seems cleaner.


/etc/puppet/modules/wufirewall/manifests/prev4.pp:
class wufirewall::prev4 {
  Firewall {
    require => undef,
  }
  # Default firewall rules
  firewall { '000 accept all icmp':
    proto   => 'icmp',
    action  => 'accept',
    provider => 'iptables',
  }
  firewall { '001 accept all to lo interface':
    proto   => 'all',
    iniface => 'lo',
    action  => 'accept',
    provider => 'iptables',
  }
  firewall { '002 accept related established rules':
    proto   => 'all',
    state   => ['RELATED', 'ESTABLISHED'],
    action  => 'accept',
    provider => 'iptables',
  }
  firewall { '010 allow ssh from Desktop Network':
    dport   => '22',
    proto  => 'tcp',
    source => '192.168.0.0/24',
    action => 'accept',
    provider => 'iptables',
  }
}

/etc/puppet/modules/wufirewall/manifests/prev6.pp:
class wufirewall::prev6 {
  Firewall {
    require => undef,
  }
  # Default firewall rules
  firewall { '000 ip6 accept all icmpv6':
    proto   => 'ipv6-icmp',
    action  => 'accept',
    provider => 'ip6tables',
  }
  firewall { '001 ip6 accept all to lo interface':
    proto   => 'all',
    iniface => 'lo',
    action  => 'accept',
    provider => 'ip6tables',
  }
  firewall { '002 ip6 accept related established rules':
    proto   => 'all',
    state   => ['RELATED', 'ESTABLISHED'],
    action  => 'accept',
    provider => 'ip6tables',
  }
  firewall { '011 ip6 allow sshv6 from desktop':
    dport   => '22',
    proto  => 'tcp',
    source => 'fe80::1/128',
    action => 'accept',
    provider => "ip6tables",
  }
}

/etc/puppet/modules/wufirewall/manifests/postv4.pp:
class wufirewall::postv4 {
  firewall { '900 log all drop connections':
    proto   => 'all',
    jump  => 'LOG',
    limit => '5/min',
    log_prefix => 'IPTables-Rejected: ',
    provider => 'iptables',
  }->
  firewall { '950 drop udp':
    proto   => 'udp',
    reject => 'icmp-port-unreachable',
    action  => 'reject',
    provider => 'iptables',
  }->
  firewall { '951 drop tcp':
    proto   => 'tcp',
    reject => 'tcp-reset',
    action  => 'reject',
    provider => 'iptables',
  }->
  firewall { '952 drop icmp':
    proto   => 'icmp',
    action  => 'drop',
    provider => 'iptables',
  }->
  firewall { '999 drop everything else - this is the failsafe rule':
    proto   => 'all',
    action  => 'drop',
    provider => 'iptables',
    before  => undef,
  }
}
/etc/puppet/modules/wufirewall/manifests/postv6.pp:
class wufirewall::postv6 {
  firewall { '900 ip6 log all drop connections':
    proto   => 'all',
    jump  => 'LOG',
    limit => '5/min',
    log_prefix => 'IPTables-Rejected: ',
    provider => 'ip6tables',
  }->
  firewall { '950 ip6 drop udpv6':
    proto   => 'udp',
    reject => 'icmp6-port-unreachable',
    action  => 'reject',
    provider => 'ip6tables',
  }->
  firewall { '951 ip6 drop tcp':
    proto   => 'tcp',
    reject => 'tcp-reset',
    action  => 'reject',
    provider => 'ip6tables',
  }->
  firewall { '952 ip6 drop icmp':
    proto   => 'icmp',
    action  => 'drop',
    provider => 'ip6tables',
  }->
  firewall { '999 ip6 drop everything else - this is the failsafe rule':
    proto   => 'all',
    action  => 'drop',
    provider => 'ip6tables',
    before  => undef,
  }
}

Here is where I am going to start putting all our one-off server rules.   We can create classes for common services like web, mail, dns, etc... But most of our systems run one off solutions that don't fit well into these categories.

/etc/puppet/modules/wufirewall/manifests/ubuntu_example_com.pp:
class wufirewall::ubuntu_example_com {
  firewall { '700 puppet on lab server':
    dport   => '8140',
    proto  => 'tcp',
    action => 'accept',
  }
}

Call the modules, here is the master site.pp...


/etc/puppet/manifests/site.pp:

## All servers get users managed by default
node 'default' {
  include manageusers
  include sudo
}
## Everything else should be explicitly set
node 'common' {
  include epel
  include wufirewall
  include sudo
  include manageusers
  include resolvconf
  include apt
  include munin
  include nrpe
  include rdiffbackup
  include syslog
  include openvmtools
}
node 'ubuntu.example.com' inherits 'common' {
  include wufirewall::ubuntu_example_com



So far most everything is working as expected:

jemurray@ubuntu:~$ sudo iptables --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     icmp --  anywhere             anywhere             /* 000 accept all icmp */
ACCEPT     all  --  anywhere             anywhere             /* 001 accept all to lo interface */
ACCEPT     all  --  anywhere             anywhere             /* 002 accept related established rules */ state RELATED,ESTABLISHED
.......
LOG        all  --  anywhere             anywhere             /* 900 log all drop connections */ limit: avg 5/min burst 5 LOG level warning prefix "IPTables-Rejected: "
REJECT     udp  --  anywhere             anywhere             /* 950 drop udp */ reject-with icmp-port-unreachable
REJECT     tcp  --  anywhere             anywhere             /* 951 drop tcp */ reject-with tcp-reset
DROP       icmp --  anywhere             anywhere             /* 952 drop icmp */
DROP       all  --  anywhere             anywhere             /* 999 drop everything else - this is the failsafe rule */



One issue I am having is that when rules are removed from ip6tables, they are NOT actually removed from the running config.  Basically the 'purge' function is not working.   Still researching why.  Based on the forums other people are having the same problem.


This is my first run though this.   The rules need to be examined more thoroughly, more testing needs to be done, at this it is very beta.    I am more interested to validate I am on the right track....


Comments?

1 comment:

  1. Hi Jason,

    Were you able to fix the purge problem? Is there a new version of this code?

    Thanks

    ReplyDelete

Followers