Best practices: iptables

Anyone who has used iptables before has locked themselves out of a remote server at least once. It’s easily avoided, but often forgotten. Lots of people have asked me for a list of best practices for iptables firewalls and I certainly hope this post helps.

Understand how iptables operates
Before you can begin using iptables, you need to fully understand how it matches packets with chains and rules. There is a terrific diagram in Wikipedia that will make it easier to understand. It’s imperative to remember that iptables rules are read top-down until a matching rule is found. If no matching rule is found, the default policy of the chain will be applied (more on that in a moment).

Don’t set the default policy to DROP
All iptables chains have a default policy setting. If a packet doesn’t match any of the rules in a relevant chain, it will match the default policy and will be handled accordingly. I’ve seen quite a few users set their default policy to DROP, and this can bring about some unintended consequences.

Consider a situation where your INPUT chain contains quite a few rules allowing traffic, and you’ve set the default policy to DROP. Later on, another administrator logs into the server and flushes the rules (which isn’t a good practice, either). I’ve met quite a few good systems administrators who are unaware of the default policy for iptables chains. Your server will be completely inaccessible immediately. All of the packets will be dropped since they match the default policy in the chain.

Instead of using the default policy, I normally recommend making an explicit DROP/REJECT rule at the bottom of your chain that matches everything. You can leave your default policy set to ACCEPT and this should reduce the chance of blocking all access to the server.

Don’t blindly flush iptables rules
Before running iptables -F, always check each chain’s default policy. If the INPUT chain is set to DROP, you’ll need to set it to ACCEPT if you want to access the server after the rules are flushed. Also, consider the security implications of your network when you clear the rules. Your services will be completely exposed and any masquerading or NAT rules will be removed.

Remember localhost
Lots of applications require access to the lo interface. Ensure that you set up your rules carefully so that the lo interface is not disturbed.

Split complicated rule groups into separate chains
Even if you’re the only systems administrator for your particular network, it’s important to keep your iptables rules manageable. If you have a certain subset of rules that may be a little complicated, consider breaking them out into their own chain. You can just add in a jump to that chain from your default set of chains.

Use REJECT until you know your rules are working properly
When you’re writing iptables rules, you’ll probably be testing them pretty often. One way to speed up that process is to use the REJECT target rather than DROP. You’ll get an immediate rejection of your traffic (a TCP reset) instead of wondering if your packet is being dropped or if it’s making it to your server at all. Once you’re done with your testing, you can flip the rules from REJECT to DROP if you prefer.

For those folks working towards their RHCE, this is a huge help during the test. When you’re nervous and in a hurry, the immediate packet rejection is a welcomed sight.

Be stringent with your rules
Try to make your rules as specific as possible for your needs. For example, I like to allow ICMP pings on my servers so that I can run network tests against them. I could easily toss a rule into my INPUT chain that looks like this:

iptables -A INPUT -p icmp -m icmp -j ACCEPT

However, I don’t want to simply allow all ICMP traffic. There have been some ICMP flaws from time to time and I’d rather keep as low of a profile as possible. There are many types of ICMP control messages, but I only want to allow echo requests:

iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

This will allow echo requests (standard ICMP pings), but it won’t explicitly allow any other ICMP traffic to pass through the firewall.

Use comments for obscure rules
If you have rules to cover edge cases that other administrators might not understand, consider using iptables comments by adding the following arguments to your rules:

-m comment --comment "limit ssh access"

The comments will appear in the iptables output if you list the current rules. They will also appear in your saved iptables rules.

Always save your rules
Most distributions offer some way to save your iptables rules so that they persist through reboots. Red Hat-based distributions offer /etc/init.d/iptables save, but Debian and Ubuntu require some manual labor. An errant reboot would easily take out your unsaved rules, so save them often.

Comments

  1. says

    Major,
    I was wondering if you had a set of rules you like to use on new slices at slicehost? One thing I’ve been struggling to find is a simple/easy way to protect eth1 on the slices, the general rules allowing 80/443 inbound are fine, but I only want to allow inbound 3306 from specific ips, or some other ports (munin nodes).. luckily munin and mysql have their own ACL’s, but i’d really like a simple way of saying allow inbound access on port 3306 from these 3 ips only.

  2. says

    Vid –

    I don’t really have a specific ruleset to be honest. I normally just toss together some relevant rules for the particular instance I’m running. If you want to allow access on port 3306 for three IP addresses that aren’t in continuous IP space, you’d have to write three separate rules for it.

  3. says

    Vid –

    I like to make bash scripts to make my firewall.. You could use something similar.. Just create an array with your allowed ports and one with your allowed hosts. Then loop though the arrays accepting traffic from those hosts on the allowed ports. Here is an example if what I use. http://systemsninja.com/firewall.txt It does use a default drop policy which goes against this blog, but that can be changed with ease :-)

    Rackerhacker –
    Is there any benefit other than what you named to not using a default DROP policy? I ask because a book I just finished reading: Linux Firewalls: Attack Detection and Response with iptables, psad, and fwsnort suggested using a default drop policy. I did find moving to the default DROP made it very annoying for the first few hours while debugging trying to get my backups and system updates working (had to allow the outbound ftp AND http traffic).

  4. says

    errr –

    Not really. I’ve just found that even the most seasoned systems administrators will overlook the policy line on a chain if they’re not used to looking for it. I normally check it when I log into a server that I don’t normally administer, but that’s only because I’ve been burned many times by it. :-)

  5. Twirrim says

    I’ve been burned by “iptables -F” on a system using default DROP a stupid number of times. I very rarely take drastic steps like flushing, so I’d have hoped it would sink in, but usually it doesn’t until I twig I’ve locked myself out of a server again.

    A couple of suggestions:
    1) Carry out iptables actions from inside a “screen” session, particularly with chains of commands (as my understanding goes). This for one makes sure all the actions will be carried out, but also means that if you have accidentally screwed up you can re-attach and pick up where you left off from whatever other method you can use to get onto the server (different IP address, remote hands service(?)).

    2) Have a “get out of jail free” card ready to hand. Either within the context of a screen session, or through the ‘at’ scheduler, have something in place to restore a working iptables configuration set for xx seconds / minutes in the future. Do your potentially disruptive thing, see if you’ve still got connectivity and if you have, stop that scheduled restore.

    iptables aren’t as complicated as some people would have you believe (whilst being incredibly powerful), but it is easy to make mistakes that you’re often better approaching it from the perspective “I’m going to screw up” and ensure you’ve covered your arse appropriately :D

  6. Anonymous Coward says

    “good systems administrators who are unaware of the default policy” in an oxymoron.

  7. says

    I’d say that, if your staff need to be told these best practices, you should seriously consider introducing an iptables wrapper like firehol, ferm or shorewall. There are others, these are just the ones I’ve used with success. These three are listed in order of their policy langauges’ readability.

    Not only do wrappers offer highly readable policy languages (some more readable than others), they usually provide a toolchain that adds some protection against foot shooting. For example, “firehol try” will:

    1) save your active ruleset
    2) load the candidate ruleset
    3) wait for 30 seconds for you to type “commit”
    4) roll back to the saved ruleset if you don’t.

    I cut my teeth on raw iptables, and I enjoyed showing off my iptables fu in front of others. But the flush of pride isn’t worth the headache of having less experienced staff trip up all over your ruleset and toolchain.

    This makes it extremely easy to avoid locking yourself out of a box. And all three of the wrappers I listed above embody all of your best practices, except perhaps for “Be stringent with your rules”.

    I appreciate that there are some arguments against wrappers. I used to spout all of these:

    1) if you can’t drive iptables, you shouldn’t be operating a firewall
    2) wrappers produce inefficient rulesets
    3) you learn one wrapper, then find yourself lost when it comes to raw iptables.

    In fact, I found none of this to matter when my business serviced numerous corporate firewall customers. What I found was:

    1) wrappers made it possible for my staff to do -most- of the work
    2) wrapper inefficiency only made a measurable difference for one, highly specialized firewall
    3) staff took at interest in the generated raw iptables, using the wrapper as a learning aid.

    Ciao,
    Sheldon.

  8. says

    I have had lots of problems on my server becouse of iptables. But informations that you give helped me a lot. Thanks for post.

  9. Andrew says

    I appreciate what you’re trying to do here, but I got as far as ‘Don’t set the default policy to DROP’ and stopped reading. I I was hoping to find good IPtables specific stuff but this flies in the face of the most basic of best practices for any firewall, guaranteeing that ports which are not supposed to be open will temporarily be open while loading your rules.

    You’re right, flushing tables is dangerous, and if you do it manually you will make mistakes. Sheldon Hearn has written an excellent response, so I won’t repeat his points.

  10. says

    Assuming comments got lost in a migration to Disqus, I’m taking the liberty of repeating my comment. Apologies if you deleted it intentionally.

    I’d say that, if your staff need to be told these best practices, you should seriously consider introducing an iptables wrapper like firehol, ferm or shorewall. There are others, these are just the ones I’ve used with success. These three are listed in order of their policy langauges’ readability.

    Not only do wrappers offer highly readable policy languages (some more readable than others), they usually provide a toolchain that adds some protection against foot shooting. For example, “firehol try” will:

    1) save your active ruleset
    2) load the candidate ruleset
    3) wait for 30 seconds for you to type “commit”
    4) roll back to the saved ruleset if you don’t.

    I cut my teeth on raw iptables, and I enjoyed showing off my iptables fu in front of others. But the flush of pride isn’t worth the headache of having less experienced staff trip up all over your ruleset and toolchain.

    This makes it extremely easy to avoid locking yourself out of a box. And all three of the wrappers I listed above embody all of your best practices, except perhaps for “Be stringent with your rules”.

    I appreciate that there are some arguments against wrappers. I used to spout all of these:

    1) if you can’t drive iptables, you shouldn’t be operating a firewall
    2) wrappers produce inefficient rulesets
    3) you learn one wrapper, then find yourself lost when it comes to raw iptables.

    In fact, I found none of this to matter when my business serviced numerous corporate firewall customers. What I found was:

    1) wrappers made it possible for my staff to do -most- of the work
    2) wrapper inefficiency only made a measurable difference for one, highly specialized firewall
    3) staff took at interest in the generated raw iptables, using the wrapper as a learning aid.

    Ciao,
    Sheldon.

  11. rackerhacker says

    Hey Sheldon,

    The import is stuck at Disqus and I’m still waiting now (almost 24 hours later) for the import to complete. The comments should be back pretty soon (I hope!).

  12. Don Smith says

    Just curious about only allowing echo requests (type 8) and not replies (type 0). Does that mean that people can ping your server but, if you ping them you don’t get a response back? If you ping outbound does the reply get blocked or is it allowed back in somehow like a TCP stateful connection would be?

  13. Kees says

    “Most distributions offer some way to save your iptables rules so that they persist through reboots. Red Hat-based distributions offer /etc/init.d/iptables save, but Debian and Ubuntu require some manual labor.”

    No they don’t, at least Debian doesn’t. Just install iptables-persistent.

  14. Arka says

    To prevent foot shooting you can basically use a scheduled cron script which check every mins that you have at least an SSH access allowed in input/output for a specific IP.

  15. Arka says

    I forgot to mention that the choice of using an ACCEPT Policy for INPUT CHAIN could be use to redirect all packets into a User Chain. What’s the purpose? It allows to REJECT (by adding a REJECT rules at the end of your set) a packet instead of DROPPING and then give an answer at the source of the packet. You cannot set a REJECT policy so this is a workaround. It could be used for debug purpose or just to liberate bandwith (for proper requests obviously, script kiddies and scanners/dos are another debate).

    Hope this answer your question Vid !

Trackbacks

Leave a Reply

Your email address will not be published. Required fields are marked *