[CentOS ]IPTABLES – How Secure & Best Practice

Home » CentOS » [CentOS ]IPTABLES – How Secure & Best Practice
CentOS 16 Comments

Dear Members

I hope you are all doing well.

I am busy teaching myself iptables and was wondering if I may get some advise. The scenario is the following:

1. Default policy is to block all traffic
2. Allow web traffic and SSH
3. Allow other applications

I have come up with the following:


iptables -F
service iptables save

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# —————————————————-

16 thoughts on - [CentOS ]IPTABLES – How Secure & Best Practice

  • It’s only as secure as your web stack (and, in your case, SSH

    Packet filtering is a necessary security tool, but it’s not sufficient for total security. Much harder is auditing the pieces of your applications:

    * locked-down application configuration(s),
    * decent password policy,
    * access controls (mandatory and discretionary) that limit exposure
    to exploits or vulnerabilities,
    * timely patching,
    * good service monitoring combined with a remediation plan should
    things go awry,
    * good crypto configuration,
    * etc., etc.

    In other words, packet filtering is a good start toward a secure system, but no more than that.

  • Hello Leon.

    In addition to everything else mentioned in this thread, I’d recommend you a great book on the topic.
    “Attack Detection and Response with iptables, psad, and fwsnort by Michael Rash”
    It contains a really nice and detailed guide on iptables and most common attacks, nmap, psad and snort. Regarding your config, I’d like to point several things:
    1. You’re not dropping packets in status ‘INVALID’ on top of your script, which is strange regarding you have 3 rules to detect other non-standard behavior;
    2. Since you’re blocking outgoing UDP, you should be certain that all UDP services are set up to use TCP instead and add corresponding rules for them. I’m talking about DNS queries and NTP time sync requests (as most common, but not limited to). These services using UDP, but you disabled it and haven’t created outgoing rule for DNS over TCP or NTP using TCP. You can’t do DNS queries, and it’s almost always painful for any service you’re running on your server;
    3. Seems strange that you haven’t added SMTP to the list of allowed outgoing connections.

    29.06.2016, 13:01, “Leon Vergottini” :

    29.06.2016, 13:01, “Leon Vergottini” :

  • Why would you save the existing rule set? This script throws it away later, when it runs save again.

    By putting these rules first, before the “ESTABLISHED,RELATED” rule, you’re applying additional processing (CPU time) to the vast majority of your packets for no reason. The “E,R” rule should be first. It won’t match the invalid packets you’re trying to drop.

    You’re not specifying the “new” state in any of your input ACCEPT rules, which means that you’re also ACCEPTing invalid packets that don’t match the handful of invalid states you DROPped earlier.

    What? Why? Do you like really slow DNS? (If you don’t care about your own lookups, turn the question around. Do you like putting extra load on your DNS server, impacting service for all of its other users?)

    These are the same INPUT rules you specified earlier. You probably meant the OUTPUT chain, but you didn’t allow DNS anywhere, so you’ve broken the most important service imaginable.

    I understand what you’re trying to do, but in the real world, this will decrease performance.

    It’s not great. Use firewalld. Your rules fail to do some things both correctly and quickly that firewalld gets right. You also don’t improve on firewalld’s rule sets in any way.

  • You shouldn’t script iptables like this and instead use iptables-save and iptables-restore to activate the rules atomically and with some error checking.


  • He flushes all the tables, then saves an empty iptables configuration. Later he adds to that empty iptables configuration.

    Long-winded, but nothing wrong. Don’t forget he is a learner (leerling)
    No person is perfect when starting to learn a new system.

    Only by experimenting will one learn.

  • And I from you.

    The funny thing is that I have my rule set with exactly the same default DROP policy for all chains and several DROP rules at the beginning of my script. I must have read the same document as you and forgot all about it – time and memory don’t seem to want to play together in my noggin!

    Cheers, ak.

  • Saving doesn’t “add” to the empty configuration, it replaced the empty config. I didn’t say it was wrong, I said the saved rules are thrown away. The initial call to save is completely pointless.

  • Gordon,

    I appreciate your observations. I’ve been using iptables for a long time and still don’t really know how to configure the order of rules to optimize performance while providing thorough filtering as a component of security. Can you share links and/or other sources and guides on this subject.

    Thank you.

  • Hi Mike,

    If I may reply…

    The premise is simple, rules are located in chains. Chains of rules are evaluated from top to bottom, until the packet being evaluated matches a rule. You want to order your rules so that packets pass through as few rules as possible, i.e they are matched and either accepted or rejected as soon as possible. Each time a packet is evaluated against a rule it is using CPU cycles, so the fewer the better.

    Of course the number of rules evaluated will depend on the packet. For example, if you run a mail server receiving 1,000 emails per day, a web server with 10,000 hits per day and a DNS server with 100,000 queries per day, it makes sense to order your rules to accept the DNS queries first, followed by http traffic, and to accept the SMTP traffic last.

    This ordering would cause 111,000 packets to be evaluated by the first rule, 11,000 by the second rule and 1,000 by the third rule giving a total of 123,000 times a packet was inspected by a rule. If we reversed the order we would see 111,000 for our first rule, 110,000 for our second rule and 100,000 for our third rule, giving a total of 321,000
    examinations which is 2.6 times more than our first example. Don’t forget it’s only the initial (first) packet of each connection that is passing down through our chain of rules – all subsequent packets would be matched against our Established,Related SPI rule which is typically placed at the very top of the chain so our firewall doesn’t have to examine every packet of that 100MB email you just received in the same way as it examines the first packet. This is the rule that will always by far match the most packets hence why it’s always placed near or at the top of the chain.

    This is a very simplistic approach but you get the idea.

    As things get more complicated, you can create user-defined chains to filter off certain traffic for further examination, maybe logging action and/or rate-limiting, rather than subjecting all packets to that extra scrutiny where it is not applicable thus improving the overall efficiency. You want to make the flow of packets through the firewall as efficient as possible. This approach is only really needed where you want a given packet to be evaluated by two or more rules (e.g, log the packet then drop it).

    In reality most modern hardware is more than capable of achieving throughput that isn’t going to be rate limiting even with quite complex rule sets, but we all like to optimise stuff anyway don’t we :-)

  • Ned,

    Thank you very much for the response. Great example following through on the premise. It sounds like I need to have a better understanding of the traffic patterns on my network to know the optimal order for iptables filtering rules.

    My brief example –

    Premise: I want to limit outsiders from interfering with LAN client machines. So, I have the following rules regarding forwarding traffic:

    -A FORWARD -m state –state INVALID -j DROP
    -A FORWARD -p tcp –tcp-flags ACK,FIN FIN -j DROP
    -A FORWARD -p tcp –tcp-flags ACK,PSH PSH -j DROP
    -A FORWARD -p tcp –tcp-flags ACK,URG URG -j DROP
    -A FORWARD -p tcp –tcp-flags FIN,RST FIN,RST -j DROP
    -A FORWARD -p tcp –tcp-flags SYN,FIN SYN,FIN -j DROP
    -A FORWARD -p tcp –tcp-flags SYN,RST SYN,RST -j DROP
    -A FORWARD -p tcp –tcp-flags ALL ALL -j DROP
    -A FORWARD -p tcp –tcp-flags ALL NONE -j DROP
    -A FORWARD -p tcp –tcp-flags ALL FIN,PSH,URG -j DROP
    -A FORWARD -p tcp –tcp-flags ALL SYN,FIN,PSH,URG -j DROP
    -A FORWARD -p tcp –tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
    -A FORWARD -i LAN-NIC -s -o INET-NIC -m state –state NEW -j ACCEPT
    -A FORWARD -i INET-NIC -o LAN-NIC -d -m state –state NEW -j ACCEPT

    But I don’t know if this is interfering with, or delaying DNS requests between LAN clients and the DHCP server.

  • Try running:

    iptables -nv -L

    which will show you in the left hand column a counter for the number of packets that has matched each rule. That will give you an exact breakdown of how often your rules are being hit.

    The first thing I would do is move your ESTABLISHED,RELATED rule to the top of the chain. Once you’ve accepted the first packet you may as well accept the rest of the stream as quickly and efficiently as possible as you’ve established the connection is not malicious.

    What is the default policy for the FORWARD table? Assuming it is accept then the last two accept rules can be removed.

    The FORWARD chain only processes packets being router through the machine, so in your case that would be packets from the lan destined for the wan, or packets from the wan destined to the lan. All internal lan traffic such as dns requests from clients to the dchp server are internal and not subject to the FORWARD chain. Of course the dhcp server probably forwards those dns requests to a dns server outside of the lan so those requests will pass through the FORWARD chain at that point.

    Assuming your hardware is not crippled or the cpu constantly overloaded, it’s not going to have any problems routing traffic through your rule set. But if you want to ensure particular traffic is processed quickly and bypasses all other rules, place a rule matching it near the top to accept that traffic. For example, if you trust all traffic coming from inside your network that is destined for the outside and want to pass that traffic without testing for all those tcp flags (and any other rules), you could do something like:

    -A Forward -p all -i LAN-NIC -o INET-NIC -j ACCEPT

  • Yes!
    Much sunlight awakening crusty synapses here. :-)

    Yes – this is by far the rule with the most packets and bytes. The rule goes to the top.

    Probably a little paranoid, but all my filter policies are “DROP”

    I’m definitely going to test a few different configurations. Your input is really appreciated; great nudge!

    Best regards,