Setup Basic Iptables Firewall on Centos 6 Web Server

Iptables should be installed by default on all CentOS 5.x and 6.x installations. Check to see if iptables is installed on system by:

#rpm -q iptables

If not installed yet, iptables can install by:

#yum install iptables

Run the following commands to start Iptables and run on boot

#chkconfig iptables on

And to see if iptables is actually running:

#service iptables status

Check iptables currently loaded rules modules:

#iptables -L -n

Now Set Up a Basic Iptables Firewall on Centos 6 from Digital Ocean 

Decide which ports and services to open
First, we want to leave SSH port open so we can connect to the VPS remotely: that is port 22.

Also, we need port 80 and 443 (SSL port) for web traffic.

For sending email, we will open port 25 (regular SMTP) and 465 (secure SMTP).

To let users receive email, we will open the usual port 110 (POP3) and 995 (secure POP3 port).

Additionally, we’ll open IMAP ports, if we have it installed: 143 for IMAP, and 993 for IMAP over SSL. Note: It is recommended to only allow secure protocols, but that may not be an option, if we cannot influence the mail service users to change their email clients. Block the most common attacks.

First we flush the firewall rules – that is, erase them all:

#iptables -F

We can then add a few simple firewall rules to block the most common attacks, to protect our VPS from script-kiddies. We can’t really count on iptables alone to protect us from a full-scale DDOS or similar, but we can at least put off the usual network scanning bots that will eventually find our VPS and start looking for security holes to exploit. First, we start with blocking null packets.

#iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP

We told the firewall to take all incoming packets with tcp flags NONE and just DROP them. Null packets are, simply said, recon packets. The attack patterns use these to try and see how we configured the VPS and find out weaknesses. The next pattern to reject is a syn-flood attack.

#iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

Syn-flood attack means that the attackers open a new connection, but do not state what they want (ie. SYN, ACK, whatever). They just want to take up our servers’ resources. We won’t accept such packages. Now we move on to one more common pattern: XMAS packets, also a recon packet.

#iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP

Allow iptables to respond to ping requests from outside network to our VPS server

#iptables -I INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT

We have ruled out at least some of the usual patterns that find vulnerabilities in our VPS. Open up ports for selected services. Now we can start adding selected services to our firewall filter. The first such thing is a localhost interface:

#iptables -A INPUT -i lo -j ACCEPT

We tell iptables to add (-A) a rule to the incoming (INPUT) filter table any trafic that comes to localhost interface (-i lo) and to accept (-j ACCEPT) it. Localhost is often used for, ie. your website or email server communicating with a database locally installed. That way our VPS can use the database, but the database is closed to exploits from the internet. Now we can allow web server traffic:

#iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
#iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

We added the two ports (http port 80 and https port 443) to the ACCEPT chain – allowing traffic in on those ports. Now, let’s allow users use FTP and SMTP servers:

#iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
#iptables -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
#iptables -A INPUT -p tcp -m tcp --dport 465 -j ACCEPT

Like stated before, if we can influence our users, we should rather use the secure version, but often we can’t dictate the terms and the clients will connect using port 25, which is much more easier to have passwords sniffed from. We now proceed to allow the users read email on their server:

#iptables -A INPUT -p tcp -m tcp --dport 110 -j ACCEPT
#iptables -A INPUT -p tcp -m tcp --dport 995 -j ACCEPT

Those two rules will allow POP3 traffic. Again, we could increase security of our email server by just using the secure version of the service. Now we also need to allow IMAP mail protocol:

#iptables -A INPUT -p tcp -m tcp --dport 143 -j ACCEPT
#iptables -A INPUT -p tcp -m tcp --dport 993 -j ACCEPT

Limiting SSH access

We should also allow SSH traffic, so we can connect to the VPS remotely. The simple way to do it would be with this command:

#iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

We now told iptables to add a rule for accepting tcp traffic incomming to port 22 (the default SSH port).

Find out your outside IP address by type:

# w
11:42:59 up 60 days, 11:21, 1 user, load average: 0.00, 0.00, 0.00
USER TTY FROM [email protected] IDLE JCPU PCPU WHAT
root pts/0 213.191.xxx.xxx 09:27 0.00s 0.05s 0.00s w

Now, you can create the firewall rule to only allow traffic to SSH port if it comes from your IP address:

#iptables -A INPUT -p tcp -s YOUR_IP_ADDRESS -m tcp --dport 22 -j ACCEPT

Replace YOUR_IP_ADDRESS with the actuall IP, of course.

We could open more ports on our firewall as needed by changing the port numbers. That way our firewall will allow access only to services we want.
Add one more rule that will allow us to use outgoing connections (ie. ping from VPS or run software updates);

#iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

It will allow any established outgoing connections to receive replies from the VPS on the other side of that connection. When we have it all set up, we will block everything else, and allow all outgoing connections.

#iptables -P OUTPUT ACCEPT
#iptables -P INPUT DROP

Now we have our firewall rules in place. Save the configuration.
Now that we have all the configuration in, we can list the rules to see if anything is missing.

#iptables -L -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTAB       LISHED
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp flags:0x3F/0x00       
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp flags:!0x17/0x0       2 state NEW
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp flags:!0x17/0x0       2 state NEW
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp flags:0x3F/0x3F       
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:443
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:25
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:465
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:110
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:995
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:143
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:993
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

The -n switch here is because we need only ip addresses, not domain names. Ie. if there is an IP in the rules like this: 69.55.48.33: the firewall would go look it up and see that it was a digitalocean.com IP. We don’t need that, just the address itself. Now we can finally save our firewall configuration:

#iptables-save | tee /etc/sysconfig/iptables
# Generated by iptables-save v1.4.7 on Sat May 14 05:05:52 2016
*raw
:PREROUTING ACCEPT [5758:5496095]
:OUTPUT ACCEPT [3894:466098]
COMMIT
# Completed on Sat May 28 05:05:52 2016
# Generated by iptables-save v1.4.7 on Sat May 14 05:05:52 2016
*mangle
:PREROUTING ACCEPT [5758:5496095]
:INPUT ACCEPT [5758:5496095]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [3894:466098]
:POSTROUTING ACCEPT [3894:466098]
COMMIT
# Completed on Sat May 28 05:05:52 2016
# Generated by iptables-save v1.4.7 on Sat May 14 05:05:52 2016
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [12:2592]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j        DROP
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j        DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,U       RG -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 465 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 110 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 995 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 143 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 993 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
COMMIT
# Completed on Sat May 14 05:05:52 2016
# Generated by iptables-save v1.4.7 on Sat May 14 05:05:52 2016
*nat
:PREROUTING ACCEPT [194:11875]
:POSTROUTING ACCEPT [189:13643]
:OUTPUT ACCEPT [189:13643]
COMMIT
# Completed on Sat May 14 05:05:52 2016

The iptables configuration file on CentOS is located at /etc/sysconfig/iptables. The above command saved the rules we created into that file. Just to make sure everything works, we can restart the firewall:

#service iptables restart
iptables: Setting chains to policy ACCEPT: raw mangle filte[  OK  ]
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Unloading modules:                               [  OK  ]
iptables: Applying firewall rules:                         [  OK  ]

The saved rules will persist even when the VPS is rebooted