Automate iptables using Puppet - Red Hat/CentOS

This article shows you how to Automate iptables for the whole infrastructure (linux/unix) and maintain the state during the lifecycle of a host. We would need to install 2 modules from PuppetLabs so that we can assign Rules based on the requirements, whether its from one destination to another or from one host to multiple destinations or vice-versa.

  1. puppetlabs/Firewall = Standard module for iptables.
  2. puppetlabs/Firewall_multi = Module that takes care off when adding multiple source/destination/ports in one Rule.

Assumptions before implementing iptables automation

  • Have a good understanding of how Puppet works.
  • Good understanding of Puppetmaster and nodes.
  • Good understanding of iptables in Linux (Red Hat/CentOS)

Let's start with the process. To start with we need to install 2 modules from Puppetlabs.

# puppet module install puppetlabs-firewall --version 1.8.1
# puppet module install alexharvey-firewall_multi --version 1.4.1

Now we can start off with creating manifests for automation. To start with need to create a 3 manifests.

pre.pp = There will be RULES which need to be applied first and the rest needs to be dropped. This takes care of the order in which they need to be applied.

post.pp =This is created for rules that need to be applied last so that connection doesn't drop out before the manifests are applied.

init.pp = This contains the info of the manifests and the order in which they need to be deployed. That is pre RULES needs to be applied before post RULES.

The implemntation of the above will be further clarified as we go through the article.

Create a pre.pp manifests with RULES that need to be applied before dropping any 3rd party RULES.

# mkdir -p /etc/puppet/modules/fw_rules/manifests/

pre.pp

# vi /etc/puppet/modules/fw_rules/manifests/pre.pp
class fw_rules::pre {
   Firewall {
    require => undef,
  }

#######################################
#######   IPtables CHAIN Def    #######
#######################################

firewall { '001 jump to ETH0-INPUT':
        chain   => 'INPUT',
        jump    => 'ETH0-INPUT',
        iniface => 'eth0',
}
firewall { '002 forward lo to INPUT':
        chain   => 'INPUT',
        action  => 'accept',
        iniface => 'lo',
}
firewallchain { 'ETH0-INPUT:filter:IPv4':
        ensure  => present,
}
firewall { '003 jump to ETH0-OUTPUT':
        chain   => 'OUTPUT',
        jump    => 'ETH0-OUTPUT',
        outiface => 'eth0',
}
firewall { '004 forward lo to OUTPUT':
        chain   => 'OUTPUT',
        action  => 'accept',
        outiface => 'lo',
}
firewallchain { 'ETH0-OUTPUT:filter:IPv4':
        ensure  => present,
}

NOTE: In the above I am creating a new CHAIN called ETH0-INPUT and ETH0-OUTPUT and forwarding as I have got more than one NIC on my host and want to label them accordingly.

##################################################
###############    INPUT CHAIN    ################
##################################################

firewall { '005 INPUT allow related and established': 
        state => ['RELATED', 'ESTABLISHED'],
        chain  => 'ETH0-INPUT',
        action  => 'accept',
        proto => 'all',
}
firewall_multi { '006 allow Clients - IDM DNS TCP/UDP access':
        chain  => 'ETH0-INPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => [ 'tcp', 'udp' ],
        dport => [ '88', '464', '53' ],
        source => '192.168.132.3',
}
firewall_multi { '006 allow Clients - IDM DNS TCP access':
        chain  => 'ETH0-INPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => 'tcp',
        dport => [ '80', '443', '389', '636', '464', '749' ],
        source => '192.168.132.3',
}
firewall { '006 allow Clients - IDM NTP access':
        chain  => 'ETH0-INPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => 'udp',
        dport => '123',
        source => '192.168.132.3',
}
firewall { '009 INPUT LOG requests':
        chain  => 'ETH0-INPUT',
        jump  => 'LOG',
        proto => 'all',
}
firewall { '010 INPUT DROP requests':
        chain  => 'ETH0-INPUT',
        action  => 'drop',
        proto => 'all',
}

NOTE: If you note in the above the numbers "001" "002" are very important as it decides the precedence/ranking of RULES in iptables. So 001 gets applied first and then followed by 002 ,003, 004, 005, 006 and so forth and so on. You can have more than one RULE with the same number but then the RULE will be applied alphabatical order of the comments.

##################################################
#########      OUTPUT CHAIN        ###############
##################################################

firewall { '0013 OUTPUT allow related and established':
        state => ['RELATED', 'ESTABLISHED'],
        chain  => 'ETH0-OUTPUT',
        action  => 'accept',
        proto => 'all',
}
firewall { '0018 OUTPUT allow loopback':
        iniface => 'lo',
        chain   => 'ETH0-OUTPUT',
        action    => 'accept',
}
firewall { '0014 allow PUPPET access':
        chain  => 'ETH0-OUTPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => 'tcp',
        dport => '8140',
        destination => '192.168.132.5',
}
firewall { '0015 allow LAN SSH access':
        chain  => 'ETH0-OUTPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => 'tcp',
        dport => '22',
        destination => '192.168.132.0/24',
}
firewall_multi { '0016 allow Clients - IDM DNS TCP/UDP access':
        chain  => 'ETH0-OUTPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => [ 'tcp', 'udp' ],
        dport => [ '88', '464', '53' ],
        destination => '192.168.132.3',
}
firewall_multi { '0016 allow Clients - IDM DNS TCP access':
        chain  => 'ETH0-OUTPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => 'tcp',
        dport => [ '80', '443', '389', '636', '464', '749' ],
        destination => '192.168.132.3',
}
firewall { '0016 allow Clients - IDM NTP access':
        chain  => 'ETH0-OUTPUT',
        state => ['NEW'],
        action  => 'accept',
        proto => 'udp',
        dport => '123',
        destination => '192.168.132.3',
}

NOTE: As described before now you can see the use of "firewall_multi" module in the above '0016 allow Clients - IDM DNS TCP access', its allowing input from IDM server for both TCP & UDP protocols and on multiple ports 88,464 & 53.

Now lets create the RULES for post.pp to be applied last.

post.pp

# vi /etc/puppet/modules/fw_rules/manifests/post.pp
class fw_rules::post {

firewall { '998 OUTPUT LOG Requests':
        chain => 'ETH0-OUTPUT',
        jump  => 'LOG',
        proto => 'all',
        before => undef,
}
firewall { '999 drop all':
    chain  => 'ETH0-OUTPUT',
    proto   => 'all',
    action  => 'drop',
    before  => undef,
  }
}

NOTE: Make sure that the NUMBERS following the comments are after any other rules. I have make sure that the numbers are as farther away from any other RULES i.e. 998, 999.

Now let's create the init.pp manifest that describes how the rules should be aplied.

init.pp

# vi /etc/puppet/modules/fw_rules/manifests/init.pp
class fw_rules {
    resources { "firewall":
        purge => true
    }
    Firewall {
        before  => Class['fw_rules::post'],
        require => Class['fw_rules::pre'],
    }
    class { ['fw_rules::pre', 'fw_rules::post']: }
    class { 'firewall': }
}

NOTE: fw_rules::pre will be applied before fw_rules::post are applied Note before and require in the classes. 

Now include the module in one of the nodes and run the puppet agent.

# vi /etc/puppet/manifests/site.pp
node 'nagios.off.local' {
       include fw_rules
}

Run the puppet agent on the node

# puppet agent -t

Output:

[@nagios admin]# puppet agent -t
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Info: Caching catalog for nagios.off.local
Info: Applying configuration version '1480340478'
Notice: /Stage[main]/Fw_rules::Pre/Firewallchain[ETH0-INPUT:filter:IPv4]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewallchain[ETH0-OUTPUT:filter:IPv4]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[006 allow SSH access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[006 allow Clients - IDM NTP access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[0016 allow Clients - IDM DNS TCP/UDP access]/Firewall[0016 allow Clients - IDM DNS TCP/UDP access protocol tcp]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[0013 OUTPUT allow related and established]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[0018 OUTPUT allow loopback]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[006 allow Clients - IDM DNS TCP/UDP access]/Firewall[006 allow Clients - IDM DNS TCP/UDP access protocol udp]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[006 allow Clients - IDM DNS TCP access]/Firewall[006 allow Clients - IDM DNS TCP access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[009 INPUT LOG requests]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[010 INPUT DROP requests]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[006 allow Clients - IDM DNS TCP/UDP access]/Firewall[006 allow Clients - IDM DNS TCP/UDP access protocol tcp]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[0016 allow Clients - IDM DNS TCP access]/Firewall[0016 allow Clients - IDM DNS TCP access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[001 jump to ETH0-INPUT]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[0015 allow LAN SSH access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[0016 allow Clients - IDM DNS TCP/UDP access]/Firewall[0016 allow Clients - IDM DNS TCP/UDP access protocol udp]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[004 forward lo to OUTPUT]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[003 jump to ETH0-OUTPUT]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[002 forward lo to INPUT]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[0014 allow PUPPET access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[005 INPUT allow related and established]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall_multi[0017 allow CENTOS & PUPPETLabs access]/Firewall[0017 allow CENTOS & PUPPETLabs access]/ensure: created
Notice: /Stage[main]/Fw_rules::Pre/Firewall[0016 allow Clients - IDM NTP access]/ensure: created
Notice: /Stage[main]/Fw_rules::Post/Firewall[998 OUTPUT LOG Requests]/ensure: created
Notice: /Stage[main]/Fw_rules::Post/Firewall[999 drop all]/ensure: created
Notice: /Stage[main]/Nagios::Firewall/Firewall_multi[006 allow NAGIOS WEBUI access]/Firewall[006 allow NAGIOS WEBUI access]/ensure: created
Notice: Finished catalog run in 6.25 seconds

Now when you see the rules applied in "/etc/sysconfig/iptables", it will show you the order in which the rules were applied.

# view /etc/sysconfig/iptables

Output:

Pre Rules - pre.pp

# Generated by iptables-save v1.4.7 on Mon Nov 28 19:54:06 2016
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:ETH0-INPUT - [0:0]
:ETH0-OUTPUT - [0:0]
-A INPUT -i eth0 -p tcp -m comment --comment "001 jump to ETH0-INPUT" -j ETH0-INPUT
-A INPUT -i lo -p tcp -m comment --comment "002 forward lo to INPUT" -j ACCEPT
-A OUTPUT -o eth0 -p tcp -m comment --comment "003 jump to ETH0-OUTPUT" -j ETH0-OUTPUT
-A OUTPUT -o lo -p tcp -m comment --comment "004 forward lo to OUTPUT" -j ACCEPT
-A ETH0-INPUT -m comment --comment "005 INPUT allow related and established" -m state --state RELATED,ESTABLISHED -j ACCEPT
-A ETH0-INPUT -s 192.168.132.3/32 -p tcp -m multiport --dports 80,443,389,636,464,749 -m comment --comment "006 allow Clients - IDM DNS TCP access" -m state --state NEW -j ACCEPT
-A ETH0-INPUT -s 192.168.132.3/32 -p tcp -m multiport --dports 88,464,53 -m comment --comment "006 allow Clients - IDM DNS TCP/UDP access protocol tcp" -m state --state NEW -j ACCEPT
-A ETH0-INPUT -s 192.168.132.3/32 -p udp -m multiport --dports 88,464,53 -m comment --comment "006 allow Clients - IDM DNS TCP/UDP access protocol udp" -m state --state NEW -j ACCEPT
-A ETH0-INPUT -s 192.168.132.3/32 -p udp -m multiport --dports 123 -m comment --comment "006 allow Clients - IDM NTP access" -m state --state NEW -j ACCEPT
-A ETH0-INPUT -s 192.168.132.0/24 -p tcp -m multiport --dports 443 -m comment --comment "006 allow NAGIOS WEBUI access" -m state --state NEW -j ACCEPT
-A ETH0-INPUT -s 192.168.132.0/24 -p tcp -m multiport --dports 22 -m comment --comment "006 allow SSH access" -m state --state NEW -j ACCEPT
-A ETH0-INPUT -m comment --comment "009 INPUT LOG requests" -j LOG
-A ETH0-INPUT -m comment --comment "010 INPUT DROP requests" -j DROP
-A ETH0-OUTPUT -m comment --comment "0013 OUTPUT allow related and established" -m state --state RELATED,ESTABLISHED -j ACCEPT
-A ETH0-OUTPUT -d 192.168.132.5/32 -p tcp -m multiport --dports 8140 -m comment --comment "0014 allow PUPPET access" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -d 192.168.132.0/24 -p tcp -m multiport --dports 22 -m comment --comment "0015 allow LAN SSH access" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -d 192.168.132.3/32 -p tcp -m multiport --dports 80,443,389,636,464,749 -m comment --comment "0016 allow Clients - IDM DNS TCP access" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -d 192.168.132.3/32 -p tcp -m multiport --dports 88,464,53 -m comment --comment "0016 allow Clients - IDM DNS TCP/UDP access protocol tcp" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -d 192.168.132.3/32 -p udp -m multiport --dports 88,464,53 -m comment --comment "0016 allow Clients - IDM DNS TCP/UDP access protocol udp" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -d 192.168.132.3/32 -p udp -m multiport --dports 123 -m comment --comment "0016 allow Clients - IDM NTP access" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -p tcp -m multiport --dports 80,443 -m comment --comment "0017 allow CENTOS & PUPPETLabs access" -m state --state NEW -j ACCEPT
-A ETH0-OUTPUT -i lo -p tcp -m comment --comment "0018 OUTPUT allow loopback" -j ACCEPT

Post Rules - post.pp

-A ETH0-OUTPUT -m comment --comment "998 OUTPUT LOG Requests" -j LOG
-A ETH0-OUTPUT -m comment --comment "999 drop all" -j DROP
COMMIT
# Completed on Mon Nov 28 19:54:06 2016

That's it and you now have a fully automated iptables across the infrastructure!!

If any issues, please contact us and we will be more than happy to assist you.

Infra Related Articles....

It's now possible to install both Puppet Master and Agent on the same host with different certs for each, to...
This article shows you how to Automate iptables for the whole infrastructure (linux/unix) and maintain the state during the lifecycle...
When adding multiple users in IDM/freeIPA its a pain inputting each user and its time consuming. This script/one liner allows...
This article covers the setup and configuration of PuppetDB and Puppetmaster on separate nodes/hosts. I have used PostgreSQL as PuppetDB...
The process of upgrading Red Hat Satellite 5.6 to 5.7 is fairly simple if you follow the steps properly and...
Joomla! Україна