Setting up a simple firewall in Linux
In Linux, there are a few basic concepts that we need to understand before we start.
- Firewall rules are, in general, applied as they are read, from the top down.
- The best firewall DENIES ALL and only ALLOWS what is needed.
- OUTBOUND rules are generally more relaxed than INBOUND.
- A Policy is what gets applied when there is no rule (NB!)
- Local Loop is an internal interface which applications can use to connect to each other via tcp/ip. It is also known as “localhost” or “127.0.0.1”.
Please remember that making your firewall rules stay after a reboot differs from version to version of Linux. You will have to Google where your Linux flavour saves it’s rules.
On the last point, remember that if your default POLICY is to DROP or DENY all traffic, you will lose connectivity if you clear all rules. The only way to restore connectivity is usually to reboot the server. There is a way past this, but it needs a bit of work.
What will we achieve in this basic tutorial?
We will set up a basic firewall which allows
ssh and blocks all else except
traceroute and whatever services you need to be accessed. In our sample ruleset, we will allow http and https (ports 80 and 443).
To find the port used for your application, use google to search for “Which port does … use”. Here is also a short list of commonly used ports:
Our rules, in English, are:
- Allow incoming ssh, ping, traceroute and http as well as https connections.
- Allow any traffic that was requested from an existing session (ie ssh reply).
- Deny all else incoming.
- Allow all outbound traffic.
- Allow all traffic (In, Out and Forward) on our Local Loop (lo).
- Deny all forward (we are not a router or firewall).
Always remember the direction of the data.
- From Internet to your server = INPUT.
- From your server to the internet = OUTPUT
- Any data passing through your server to an internal network = FORWARD (your server is the gateway and firewall). This last case will not be used in this article as we are keeping to basics.
This is the basic building block of all modern Linux firewalls. All the firewall below create iptables rules and are merely frontends that attempt to simplify iptables.
In iptables, our firewall rules look as follows:
# Set Policies iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT # Rules - INPUT iptables -A INPUT -i lo -j ACCEPT # Local Loop # Requested traffic from an established session iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # Accept SSH connections (single port allowed per rule) iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow ping and traceroute (ICMP traffic) iptables -A INPUT -p ICMP -j ACCEPT # Allow HTTP and HTTPS traffic (multiport allowed) iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT iptables -A INPUT -s 0.0.0.0/0 -j DROP # Rules - FORWARD iptables -A FORWARD -s 0.0.0.0/0 -j DROP # Rules - OUTPUT iptables -A OUTPUT -d 0.0.0.0/0 -j ACCEPT
There are different ways to write the rules and achieve the same. We could have added the ssh rule to the HTTP/HTTPS multiport rule. Another option is to write all the rules (SSH, HTTP and HTTPS as 3 separate rules as the SSH was written.
We could also have changed our INPUT and FORWARD policies to DROP and then left the DROP rules out of the ruleset. This may seem the better choice but can be dangerous as previously mentioned.
Once your policy DROPS all traffic not allowed, you cannot afford to clear your iptables rules for testing as your connection will then also be dropped. It is safer until you understand firewalling, to add a DROP rule at the end of your ruleset.
UFW is usually included in Ubuntu but may be installed on other versions of Linux as well. It is quite a powerful interface that simplifies many of iptables more intricate configurations.
UFW does not include the more advanced features, but they may be applied in a pre-run configuration file /etc/ufw/before.rules. Here you may add rules in iptables format without the “iptables” part. Our ruleset under UFW looks as follows:
# Set Policies 0 ufw has no forwarding and allows ICMP by default. # Related,Established is also allowed by default. ufw default allow incoming ufw default allow outgoing # Rules - Incoming ufw allow in on lo from any # Local Loop ufw allow in ssh ufw allow in http ufw allow in https ufw deny in from 0.0.0.0/0 ufw allow out to 0.0.0.0/0 # UFW can be controlled with ufw enable ufw disable ifw status
Firewalld came out with Redhat/Centos 7 and is yet another attempt to make iptables easier to use. Personally, I think it has had the opposite effect. Our rules under firewalld are as follows:
# Outbound and Related traffic is allowed by default as is ICMP firewall-cmd --set-default-zone=public firewall-cmd --zone=public --add-interface=eth0 # Our public interface is eth0 firewall-cmd --zone=public --add-service=ssh --permanent firewall-cmd --zone=public --add-service=http --permanent firewall-cmd --zone=public --add-service=https --permanent # Reload the firewall firewall-cmd --reload
This is a brilliant piece of software that watches for certain access errors such as failed passwords or attempts to call certain known weak points in your application. It will then trigger a firewall rule to block the offending IP address.
Blocking time can be configured and the block or BAN is lifted once the timer has run out. Just be aware that the most commonly used trap for fail2ban, ssh, is not always active by default and needs to be enabled.
CSF & LFD
This firewall comes with cPanel and Plesk web hosting platforms. It may also be installed separately. LFD or Login Failure Daemon is a replacement for Fail2Ban and does much the same thing.
CSF rules are usually written into the /etc/csf/csf.conf and not added or removed via the command line.
Ultimately, any firewall is better than none. Stick to the principles of only allowing what you need and you will have gone a long way to securing your server.