//jerrywalsh.org

coding, hacking, startups, computer security, technology and more

HOWTO Secure Your Linux Box With IPTABLES

Okay, so this post will be brief but to the point. Today I needed to lock down a machine I administer so the only inbound connections which were allowed were SSH connections from trusted hosts. I'm using Debian so this will obviously work for other Debian based distros such as Ubuntu, Linux Mint etc.

Assuming you're running a current version of Debian or a derivative then iptables will already be present on your system. One of the first things to take note is that iptables won't hold its ruleset during a reboot so to start off this tutorial the first thing I ensured was that the ruleset will be restored when the machine is rebooted. So, as root I edited /etc/rc.local and before the exit line i added /etc/iptables-init. Because this was a fresh install my rc.local ended up looking like this:

/etc/rc.local from Debian 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Setup iptables
/etc/iptables-init
exit 0

Next, I created the script which we've setup to be executed from rc.local:

/etc/iptables-init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/bin/sh
# ----------------------------------------------------------------------
# simple but secure iptables initialization script
# DateCreated: Thu 12 Jan 2012 00:37:04 GMT
# Author: Jerry Walsh
# ----------------------------------------------------------------------

# Put your trusted hosts/ranges here:
TRUSTED_HOSTS="1.2.3.4 8.8.8.8/24 \
  4.3.2.1 1.2.2.2 3.3.3.4 "

# flush rules
iptables -F

# Log dropped connections
#iptables -N LOGDROP

# allow localhost connections to the loopback interface 
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

# allow connections which are already established
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# allow all outbound connections
iptables -A OUTPUT -j ACCEPT

# allow tcp to port 22 (ssh daemon) from trusted hosts
for GOODIE in $TRUSTED_HOSTS; do
  iptables -A INPUT -p tcp -m state --state NEW -s $GOODIE --dport 22 -j ACCEPT
done
# or you could just allow ssh access from all hosts
# NOTE: if you're going to allow ssh access from all hosts then
# it's always a good idea to put sshd on a non-standard port
# - this keeps the majority of script kid trawlers out
#iptables -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

#other optional extras:
# allow inbound http access
#iptables -A INPUT -p tcp -m state --state NEW --dport 80 -j ACCEPT
# allow inbound https access
#iptables -A INPUT -p tcp -m state --state NEW --dport 443 -j ACCEPT

# drop all other inbound traffic (including ICMP, UDP etc.)
iptables -A INPUT -j DROP
# you could also just block tcp connections..
#iptables -A INPUT -p tcp -j DROP

Finally, I set the script executable and executed the script now to load the new rules in to iptables:

finally, we mark the script executable and run it!
1
2
chmod 0700 /etc/iptables-init
!$

And that's it! Remember - it's always good to test your configuration from a remote host or better still from a 'bad' remote host and a 'good' (whitelisted) host.

REMEMBER: The above script is just an example! You should modify the script to meet YOUR needs (as it stands this met mine) but it still serves as a useful starting point. It should also be noted that ICMP ping replies will be blocked using the above setup - this may not be desirable but in my case it was!