In this post, I’ll go over how to use iptables and ipset to create a basic firewall with ssh brute force protection and geo-blocking. I’m assuming CentOS here, adjust paths/commands accordingly for other distributions.
Ipset is a tool to create and maintain IP sets in the Linux kernel. The advantage of using ipset over setting up a bunch of individual rules is one of CPU utilization. Ipset can handle thousands of entries without CPU degradation, wheras introducing thousands of rules in iptables will have a noticeable impact on packet processing speeds.
First we’ll install the tool and create an initial ipset and persist it.
yum install ipset iptables iptables-services
cat <<EOF >/root/refresh-geoblock.sh#!/bin/bashmkdir /tmp/geoblockingcd /tmp/geoblockingipset destroy geoblockipset -N geoblock nethashfor i in cn kr pk tw sg kh pe; do echo $iwget -q http://www.ipdeny.com/ipblocks/data/countries/$i.zonefor k in `cat $i.zone`; do ipset -A geoblock $kdonedonecd /tmprm -rf /tmp/geoblockingipset save geoblock >/etc/sysconfig/ipset-geoblockEOFchmod +x /root/refresh-geoblock.sh
Next up, a basic firewall configuration. Some things to note about these rules:
Default input/output policy is set to drop. I highly recommend you leave it this way and only open up what you really need.
Poking holes for inbound SSH. These rules use the recent match and will only allow 4 connections per source IP every five minutes, which will greatly reduce the number of brute force attempts that hit the server.
Poking holes for outbound ports for github/bitbucket
Poking holes for some yum repositories
Poking holes for outbound DNS (using google’s recursive DNS resolver in this example)
If you want to use this as-is, make sure you update your /etc/resolv.conf to have the correct DNS entries.
Once this is in place, we’re good to go. You can start your fresh firewall with
service iptables start
You may want to periodically refresh your geo-blocking rules. This can be done with the following commands:
service iptables stop
service iptables start
There’s one last thing that hasn’t been addressed, it’s reloading the ipset after a reboot before the firewall gets reloaded. To address this, I’ve edited /usr/libexec/iptables/iptables.init and changed the following function: