Cfengine configuration directory

Using iptables/chains firewall rules within cfengine

Relevant classes: any

This extract was taken from help-cfengine@cfengine.org on 26/08/07
On Aug 23, 2007, at 1:19 PM, Jennings Jared L CTR USAF 46 SK/CCI wrote:

> Has anyone used cfengine to set up firewalls? If so, how did you go
> about it?

Here's the cfengine-managed firewall that I set up at the OSL, that
opens ports based on inclusion in cfengine classes.  I've pasted most
of this out of our wiki, so its pretty verbose.

The firewall init script, /etc/init.d/firewall, uses the run-parts
script to run through each of the scripts in /etc/firewall.d.  Each of
these scripts corresponds to setting up part of the foundation for the
firewall rules, or adding in service- or host-specific rules.

The /etc/conf.d/firewall configuration file provides environmental
variables to these scripts.  Currently, the scripts should use
$IPTABLES for the path to the iptables binary, $EXTERNAL for the
public-facing ethernet interface, $INTERNAL for the private network
interface, and $LOCAL for the localhost interface.

Because netfilter rules are *very* dependent on order, it is important
that the scripts in /etc/firewall.d are executed in the correct order.
To this effect, ordering numbers are prepended to the names of the
scripts (run-parts executes the scripts in alphanumeric order).  We
use the following:

||Number||Function||
|00-49  | Prep chains and core filters |
|50     | SSH |
|51-59  | High volume services (http, smtp) so we don't need to traverse as many rules |
|60-69  | Monitoring |
|70-79  | Low volume / maitainance (cfengine, backup) |
|90-99  | Host specific appends or inserts|

==EXAMPLES==

[endicott:files/etc/firewall.d] emsearcy% ls
00clear      21related    48icmp       53logging    56smtp       60postgresql 70backup     93cherry     95backup
05policies   30oslonly    50ssh        54http       57imaps      64nrpe       71cfengine   93fir        README
20internal   40badpackets 51sftp       54ldap       58rsync      66snmp       72mirror     94larch
20lo         45altchains  52ftp        55dns        59mysql      66snmp-tds   73myphpadmin 94yang
[endicott:files/etc/firewall.d] emsearcy% cat 00clear
#!/bin/bash

# Set policies to accept
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT

# Flush rules from all filter chains
$IPTABLES -F

# Delete user-added chains
$IPTABLES -X
[endicott:files/etc/firewall.d] emsearcy% cat 05policies
#!/bin/bash

# Set policies to drop incoming packets
$IPTABLES -P INPUT DROP

# Don't forward anything
$IPTABLES -P FORWARD DROP
[endicott:files/etc/firewall.d] emsearcy% cat 20lo
#!/bin/bash

# Allow localhost
$IPTABLES -A INPUT -i $LOCAL -j ACCEPT
[endicott:files/etc/firewall.d] emsearcy% cat 21related
#!/bin/bash

# Let in packets from existing connections
$IPTABLES -A INPUT -i $EXTERNAL -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -i $INTERNAL -m state --state ESTABLISHED,RELATED -j ACCEPT
[endicott:files/etc/firewall.d] emsearcy% cat 45altchains
#!/bin/bash

# Create new chains for tcp, udp, and icmp incoming traffic
$IPTABLES -N IN_TCP
$IPTABLES -N IN_UDP
$IPTABLES -N IN_ICMP

# Redirect the appropriate protocol to the new chain
$IPTABLES -A INPUT -p tcp -j IN_TCP
$IPTABLES -A INPUT -p udp -j IN_UDP
$IPTABLES -A INPUT -p icmp -j IN_ICMP
[endicott:files/etc/firewall.d] emsearcy% cat 48icmp
#!/bin/bash

# Allow ICMP pings and time exceeded messages
$IPTABLES -A IN_ICMP -p icmp -s 0/0 --icmp-type echo-request -j ACCEPT
$IPTABLES -A IN_ICMP -p icmp -s 0/0 --icmp-type time-exceeded -j ACCEPT
[endicott:files/etc/firewall.d] emsearcy% cat 50ssh
#!/bin/bash

# SSH brute-force blocking
#$IPTABLES -A IN_TCP -i $EXTERNAL -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name sshscans
#$IPTABLES -A IN_TCP -m recent --rcheck --seconds 60 --hitcount 5 --name sshscans --rsource -j DROP

# Allow all SSH that got past the sshscans list
$IPTABLES -A IN_TCP -i $EXTERNAL -p tcp --dport ssh -j ACCEPT
$IPTABLES -A IN_TCP -i $INTERNAL -p tcp --dport ssh -j ACCEPT
[endicott:files/etc/firewall.d] emsearcy% cat 54http
#!/bin/bash

$IPTABLES -A IN_TCP -i $EXTERNAL -p tcp --dport http -j ACCEPT
$IPTABLES -A IN_TCP -i $EXTERNAL -p tcp --dport https -j ACCEPT

==CONFIGS==

Most of the scripts below 50 are pulled in for all hosts, except for a
few that drop anything outside our local network or add more custom
chains.  The rest are pulled in via copy: statements for a particular
class (like service_http).  We do have some shellcommands: statements
for restarting, which are described below.

shellcommands:

    service_firewall.bounce_firewall_protect.!install_only::
        # set an `at' job to clear the firewall in 60-120 seconds
        "/bin/echo '/etc/init.d/firewall stop' | /usr/bin/at now + 2 min"
        "/etc/init.d/firewall restart"

    service_firewall.bounce_firewall_ok::
        # delete all spooled `at' jobs (if you didn't lock yourself out of the box!)
        "/usr/bin/atrm `/usr/bin/atq | sed -e 's/\W.*$//'`"

==USAGE==

As it is currently set up, cfagent will not actually converge the
machine to having the correct ports open, only to have the right
configuration for the firewall system.  Thus, it is necessary to kick
the system in order to have the correct ruleset.  In order to reduce
the possibility of locking yourself out of the box due to a
misconfigured rule (which never happens, right? :-) ), you can use
cfagent as a wrapper, which will give you a 1-2 minute buffer, after
which, if you have been locked out, the firewall will completely open
back up (it doesn't revert, just sets a global ACCEPT policy).  To
restart the firewall, run:

{{cfagent -q -D bounce_firewall_protect --just shellcommands}}

After validating that you can still log in via SSH, run this command to tell the system that it works, so it won't open the box up completely.  *Do not forget this!*

{{cfagent -q -D bounce_firewall_ok --just shellcommands}}

Of course, because this is handled through cfengine, you could also
use cfrun to push out a firewall system reload across all boxes, or
across just the class of boxes that changed.  Remember to push out the
bounce_firewall_ok class, too: if the subsequent cfrun command fails
to connect, then there was a problem and you will have to wait 1-2
minutes for the system to open itself up.

--Eric Searcy
OSU Open Source Lab

Back to documentation