Simplifing IPTABLES rule set
Simplifing IPTABLES rule set
I would like to simplify the current IPTABLES rule set for my email server. I am using IPSET to create an extensive list of CIDR blocks then referencing that list in iptables to block all traffic from those IPs. However, in my case there are only 5 subnets that need to communicate with the email server, so I thought it might be easier to block all access and then explicitly allow just the subnets that are needed. Let's assume the 5 subnets are 1.1.1.0/24, 2.2.2.0/24, 3.3.3.0/24, 4.4.4.0/24 and 5.5.50/24. I'm not worried about nailing traffic down to specific ports because I control the devices on these subnets. Will the following accomplish that?
-A INPUT -s 1.1.1.0/24 -j ACCEPT
-A INPUT -s 2.2.2.0/24 -j ACCEPT
-A INPUT -s 3.3.3.0/24 -j ACCEPT
-A INPUT -s 4.4.4.0/24 -j ACCEPT
-A INPUT -s 5.5.5.0/24 -j ACCEPT
-A INPUT -j DROP
I apologize for what is probably very basic question, but I'm doing this on a very busy live server and I want to be very careful.
Thanks, Kevin
-A INPUT -s 1.1.1.0/24 -j ACCEPT
-A INPUT -s 2.2.2.0/24 -j ACCEPT
-A INPUT -s 3.3.3.0/24 -j ACCEPT
-A INPUT -s 4.4.4.0/24 -j ACCEPT
-A INPUT -s 5.5.5.0/24 -j ACCEPT
-A INPUT -j DROP
I apologize for what is probably very basic question, but I'm doing this on a very busy live server and I want to be very careful.
Thanks, Kevin
Re: Simplifing IPTABLES rule set
Well, yes it will do what you want but it does a whole lot more than what you want too. And probably a whole lot less which might be more problematic.
First off, you are missing the standard rules that CentOS sets up out of the box:
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
The first one is important as it says "allow any packets that are in reply to packets that I've sent out". Without that, you may never get responses back to things you've attempted to talk to outside. For example, I would very much suspect that yum won't work any more...
The second one allows ICMP packets from anywhere. There are two schools of thought on this, one that says that the RFCs say you should respond to ICMP as a matter of good netiquette, the other that you should hide yourself as much as possible and never reply to them.
The third is also important as it allows all traffic on the localhost interface and there are many things that use this to talk to themselves or to other things on the same host. Without this rule or something equivalent you can expect weird stuff to fail with not much idea of why.
So those are the things you are missing and might cause you problems. The next thing is that you allow all of those subnets to talk to all ports on your server, databases, mail servers, everything that listens on your server that doesn't just listen on localhost in fact. That could be quite a lot and you are opening that up to 5 separate blocks of 256 hosts each.
Using an ipset is pretty easy, you just need a rule like this one
-A INPUT -p tcp -m set --match-set MY_IPS src -m state --state NEW -m tcp --dport 22 -j ACCEPT
and that allows all subnets/ips listed in the MY_IPS subnet to have access to port 22.
First off, you are missing the standard rules that CentOS sets up out of the box:
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
The first one is important as it says "allow any packets that are in reply to packets that I've sent out". Without that, you may never get responses back to things you've attempted to talk to outside. For example, I would very much suspect that yum won't work any more...
The second one allows ICMP packets from anywhere. There are two schools of thought on this, one that says that the RFCs say you should respond to ICMP as a matter of good netiquette, the other that you should hide yourself as much as possible and never reply to them.
The third is also important as it allows all traffic on the localhost interface and there are many things that use this to talk to themselves or to other things on the same host. Without this rule or something equivalent you can expect weird stuff to fail with not much idea of why.
So those are the things you are missing and might cause you problems. The next thing is that you allow all of those subnets to talk to all ports on your server, databases, mail servers, everything that listens on your server that doesn't just listen on localhost in fact. That could be quite a lot and you are opening that up to 5 separate blocks of 256 hosts each.
Using an ipset is pretty easy, you just need a rule like this one
-A INPUT -p tcp -m set --match-set MY_IPS src -m state --state NEW -m tcp --dport 22 -j ACCEPT
and that allows all subnets/ips listed in the MY_IPS subnet to have access to port 22.
The future appears to be RHEL or Debian. I think I'm going Debian.
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke
Re: Simplifing IPTABLES rule set
Building on what TrevorH said,
Now the policy of INPUT is DROP. Nothing is accepted without explicit rules.
The first rule in INPUT handles most of packets.
We ensure that at least 1.1.1.42 can connect even when MY_IPS is empty.
What we do with traffic from "friends" is in separate chain. You could have plain ACCEPT there as last rule if you really want.
PS.
Red Hat has backported nftables into the kernel of EL7. It is possible to run nftables.service, rather than iptables.service.
The command-line tool for nftables is nft. Nftables has "named sets" that seems to be equivalent of ipsets.
It is worthwhile to learn the syntax of nftables, because iptables is deprecated in RHEL.
Code: Select all
-N friends
-P INPUT DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -s 1.1.1.42 -j friends
-A INPUT -m set --match-set MY_IPS src -j friends
-A INPUT -j DROP
-A friends -p tcp -m state --state NEW -m tcp --dport 22 -m comment --comment "SSH" -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 443 -m comment --comment "HTTPS" -j ACCEPT
-A friends -p icmp -j ACCEPT
-A friends -m conntrack --ctstate INVALID -j DROP
-A friends -j REJECT --reject-with icmp-host-prohibited
The first rule in INPUT handles most of packets.
We ensure that at least 1.1.1.42 can connect even when MY_IPS is empty.
What we do with traffic from "friends" is in separate chain. You could have plain ACCEPT there as last rule if you really want.
PS.
Red Hat has backported nftables into the kernel of EL7. It is possible to run nftables.service, rather than iptables.service.
The command-line tool for nftables is nft. Nftables has "named sets" that seems to be equivalent of ipsets.
It is worthwhile to learn the syntax of nftables, because iptables is deprecated in RHEL.
Re: Simplifing IPTABLES rule set
TrevorH and jlehtone, I sincerely appreciate your insightful responses. Below is the current iptables script that I inherited when I took over the mail server. As I understand it, this blocks everything in the set named Block_CIDR then accepts all other traffic with the correct dport. It also allows two specific hosts to access the server via ssh. I am always modifying Block_CIDR by adding additional CIDR blocks, or removing one that has an IP in it that needs access.
At this point I would guess it's best to continue to use ipset, but for allowed addresses instead of blocked addresses. Can you suggest what that would look like? Many Thanks!
#!/bin/bash
# iptables configuration script
# Flush all current rules from iptables
iptables -F
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -N LOG_AND_DROP
iptables -A LOG_AND_DROP -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A LOG_AND_DROP -j DROP
iptables -A INPUT -m set --match-set Block_CIDR src -j LOG_AND_DROP
iptables -A INPUT -p tcp --dport 22 --source x.x.x.x/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 --source x.x.x.x/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 993 -j ACCEPT
iptables -A INPUT -p tcp --dport 25 -j ACCEPT
iptables -A INPUT -p tcp --dport 465 -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp --dport 587 -j ACCEPT
iptables -A INPUT -p tcp --dport 995 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 7071 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 10000 -j ACCEPT
iptables -A INPUT -p tcp --dport 110 -j ACCEPT
iptables -A INPUT -p tcp --dport 143 -j ACCEPT
iptables -A INPUT -p tcp --dport 8008 -j ACCEPT
iptables -P INPUT DROP
# Save settings
/sbin/service iptables save
At this point I would guess it's best to continue to use ipset, but for allowed addresses instead of blocked addresses. Can you suggest what that would look like? Many Thanks!
#!/bin/bash
# iptables configuration script
# Flush all current rules from iptables
iptables -F
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -N LOG_AND_DROP
iptables -A LOG_AND_DROP -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A LOG_AND_DROP -j DROP
iptables -A INPUT -m set --match-set Block_CIDR src -j LOG_AND_DROP
iptables -A INPUT -p tcp --dport 22 --source x.x.x.x/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 --source x.x.x.x/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 993 -j ACCEPT
iptables -A INPUT -p tcp --dport 25 -j ACCEPT
iptables -A INPUT -p tcp --dport 465 -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp --dport 587 -j ACCEPT
iptables -A INPUT -p tcp --dport 995 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 7071 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 10000 -j ACCEPT
iptables -A INPUT -p tcp --dport 110 -j ACCEPT
iptables -A INPUT -p tcp --dport 143 -j ACCEPT
iptables -A INPUT -p tcp --dport 8008 -j ACCEPT
iptables -P INPUT DROP
# Save settings
/sbin/service iptables save
Re: Simplifing IPTABLES rule set
I basically did show in my previous comment.
Note that x.x.x.x/24 looks like subnet, not one address. One host would be x.x.x.x
Note that x.x.x.x/24 looks like subnet, not one address. One host would be x.x.x.x
Re: Simplifing IPTABLES rule set
You might also look at something like fail2ban to monitor your logs and add/remove ip addresses dynamically from the block list based on their curretn activity. I'd use that in addition to your current ipset and tweak that to just ban those things that really are persistent offenders.
The future appears to be RHEL or Debian. I think I'm going Debian.
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke
Re: Simplifing IPTABLES rule set
Thank you jlehtone. So, taking your example I added what I think are the important bits from my config and came up with the following. To summarize, I will be using IPSET to create MY_IPS which will be used for friendly IPs. The friendly IPs and the two subnets that are explicitly stated are the only ones that can communicate with the server and only on the ports specified. Do I understand this correctly? Thanks again, Kevin.
#!/bin/bash
# iptables configuration script
# Flush all current rules from iptables
iptables -F
-N friends
-P INPUT DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -s x.x.x.0/24 -j friends
-A INPUT -s x.x.x.0/24 -j friends
-A INPUT -m set --match-set MY_IPS src -j friends
-A INPUT -j DROP
-A friends -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 993 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 465 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 8443 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 587 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 995 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 7071 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 10000 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 110 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 143 -j ACCEPT
-A friends -p tcp -m state --state NEW -m tcp --dport 8008 -j ACCEPT
-A friends -p icmp -j ACCEPT
-A friends -m conntrack --ctstate INVALID -j DROP
-A friends -j REJECT --reject-with icmp-host-prohibited
# Save settings
/sbin/service iptables save
Re: Simplifing IPTABLES rule set
If this is a mail server that needs to accept mail from outside sources then you will not be able to lock down port 25 to just your "friends". Anyone and everyone that sends you mail needs to be able to talk to port 25 or the mail will never be delivered.
The future appears to be RHEL or Debian. I think I'm going Debian.
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke
Re: Simplifing IPTABLES rule set
You obviously need to insert the "iptables " into those rule lines.
Bash will not undertand commands, like "-N friends". It should be "iptables -N friends".
Are the x.x.x and x.x.x different obfuscated subnets in the:
Now (only) host "a.b.c.d" can access with SSH. It can access other services too, if it is in MY_IPS.
You have 14 ports in your rules. Do you know why each of them is there?
Adding comments into the rules documents the purpose of each port and keeps that documentation "near" the rules.
Bash will not undertand commands, like "-N friends". It should be "iptables -N friends".
Are the x.x.x and x.x.x different obfuscated subnets in the:
Code: Select all
iptables -A INPUT -s x.x.x.0/24 -j friends
iptabels -A INPUT -s x.x.x.0/24 -j friends
Your new ruleset allows all "friends" to connect with ssh. That is different from your old.gtinet wrote:It also allows two specific hosts to access the server via ssh.
Code: Select all
iptables -A INPUT -s a.b.c.d -p tcp -m state --state NEW -m tcp --dport 22 -m comment --comment "Admin SSH" -j ACCEPT
iptables -A INPUT -m set --match-set MY_IPS src -j friends
# no ssh-rule in friends
You have 14 ports in your rules. Do you know why each of them is there?
Adding comments into the rules documents the purpose of each port and keeps that documentation "near" the rules.
Re: Simplifing IPTABLES rule set
Thanks again for your response jlehtone. I understand that the script will require the iptables command so I have added it here for clarification.
I removed the following two lines because those subnets will be in MY_IPS.
iptables -A INPUT -s x.x.x.0/24 -j friends
iptables -A INPUT -s x.x.x.0/24 -j friends
The remaining ports are needed by my installation of ZIMBRA Mail Server.
Can you explain the following two lines? The first one appears to accept icmp from 'friends'. The second seems to reject icmp.
iptables -A friends -p icmp -j ACCEPT
iptables -A friends -j REJECT --reject-with icmp-host-prohibited
#!/bin/bash
# iptables configuration script
# Flush all current rules from iptables
iptables -F
iptables -N friends
iptables -P INPUT DROP
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 12.34.56.78 -m comment --comment "Access from Office Public IP" -j ACCEPT
iptables -A INPUT -m set --match-set MY_IPS src -j friends
iptables -A INPUT -j DROP
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 22 -m comment --comment "SSH Access" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 443 -m comment --comment "HTTPS Webmail" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 993 -m comment --comment "SSL IMAP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 25 -m comment --comment "SMTP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 465 -m comment --comment "SSL SMTP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 8443 -m comment --comment "HTTPS Webmail" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 587 -m comment --comment "TLS SMTP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 995 -m comment --comment "SSL POP3" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 7071 -m comment --comment "Mgmt GUI" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 80 -m comment --comment "HTTP Webmail" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 10000 -m comment --comment "Mgmt GUI" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 110 -m comment --comment "POP3" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 143 -m comment --comment "IMAP" -j ACCEPT
iptables -A friends -p icmp -j ACCEPT
iptables -A friends -m conntrack --ctstate INVALID -j DROP
iptables -A friends -j REJECT --reject-with icmp-host-prohibited
# Save settings
/sbin/service iptables save
I removed the following two lines because those subnets will be in MY_IPS.
iptables -A INPUT -s x.x.x.0/24 -j friends
iptables -A INPUT -s x.x.x.0/24 -j friends
The remaining ports are needed by my installation of ZIMBRA Mail Server.
Can you explain the following two lines? The first one appears to accept icmp from 'friends'. The second seems to reject icmp.
iptables -A friends -p icmp -j ACCEPT
iptables -A friends -j REJECT --reject-with icmp-host-prohibited
#!/bin/bash
# iptables configuration script
# Flush all current rules from iptables
iptables -F
iptables -N friends
iptables -P INPUT DROP
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 12.34.56.78 -m comment --comment "Access from Office Public IP" -j ACCEPT
iptables -A INPUT -m set --match-set MY_IPS src -j friends
iptables -A INPUT -j DROP
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 22 -m comment --comment "SSH Access" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 443 -m comment --comment "HTTPS Webmail" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 993 -m comment --comment "SSL IMAP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 25 -m comment --comment "SMTP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 465 -m comment --comment "SSL SMTP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 8443 -m comment --comment "HTTPS Webmail" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 587 -m comment --comment "TLS SMTP" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 995 -m comment --comment "SSL POP3" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 7071 -m comment --comment "Mgmt GUI" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 80 -m comment --comment "HTTP Webmail" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 10000 -m comment --comment "Mgmt GUI" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 110 -m comment --comment "POP3" -j ACCEPT
iptables -A friends -p tcp -m state --state NEW -m tcp --dport 143 -m comment --comment "IMAP" -j ACCEPT
iptables -A friends -p icmp -j ACCEPT
iptables -A friends -m conntrack --ctstate INVALID -j DROP
iptables -A friends -j REJECT --reject-with icmp-host-prohibited
# Save settings
/sbin/service iptables save