How to Configure iptables on an AWS Instance

If you are looking to improve security on your AWS Amazon Linux AMI Instance, iptables can be a good start. iptables is a kernel-based firewall service, very fast and free. Note that Inbound Security is handled by AWS Security Groups, so iptables is not strictly necessary to control Inbound packets. But if you turn iptables on, you will need to allow Inbound packets in addition to the SG rules.

Where iptables can help is with Outbound Security. If someone were to somehow get access to your servers, their main priority will be escalating privileges to root. Normally to do this you would need to download a ‘hacker pack’. You can prevent this with iptables. If, however, an attacker has root permissions on your box, iptables is useless because it can just be turned off.

Here is a simple starter script to be run on the AWS Instance. This assumes that you don’t do any Outbound Connecting from Apache via PHP (eg curl), but that you do connect to an RDS Instance. You will need to ‘sudo su’ before running the script, or run the script with sudo.

#!/bin/bash

# setup basic chains and allow all or we might get locked out while the rules are running...
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

# clear rules
iptables -F

# allow HTTP inbound and replies
iptables -A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT

# allow HTTPS inbound and replies
iptables -A INPUT -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

# limit ssh connects to 10 every 10 seconds
# change the port 22 if ssh is listening on a different port (which it should be)
# in the instance's AWS Security Group, you should limit SSH access to just your IP
# however, this will severely impede a password crack attempt should the SG rule be misconfigured
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP

# allow SSH inbound and replies
# change the port 22 if ssh is listening on a different port (which it should be)
iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

# root can initiate HTTP outbound (for yum)
iptables -A OUTPUT -p tcp --dport 80 -m owner --uid-owner root -m state --state NEW,ESTABLISHED -j ACCEPT
# anyone can receive replies (ok since connections can't be initiated)
iptables -A INPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT

# root can do DNS searches (if your Subnet is 10.0.0.0/24 AWS DNS seems to be on 10.0.0.2)
# if your subnet is different, change 10.0.0.2 to your value (eg a 172.31.1.0/24 Subnet would be 172.31.1.2)
# see http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-dns.html
# DNS = start subnet range "plus two"
iptables -A OUTPUT -p udp --dport 53 -m owner --uid-owner root -d 10.0.0.2/32 -j ACCEPT
iptables -A INPUT -p udp --sport 53 -s 10.0.0.2/32 -j ACCEPT

# apache user can talk to rds server on 10.0.0.200:3306
iptables -A OUTPUT -p tcp --dport 3306 -m owner --uid-owner apache -d 10.0.0.200 -j ACCEPT
iptables -A INPUT -p tcp --sport 3306 -s 10.0.0.200 -j ACCEPT

# now drop everything else
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# save config
/sbin/service iptables save

You need to be really careful with the SSH rules – if you get them wrong, you will be locked out of your box, permanently, no fix available. Also, if you are not using SSL (or SSL is terminated on your ELB), you should remove the 2 SSL rules.

DNS access is worth a mention. To determine your DNS servers, “add 2” to your Subnet, eg 10.0.0.0/24 would be 10.0.0.2/32. Another option is to type ‘nslookup’ on the server and then something like ‘google.com’ – the first line outputted will be the DNS IP address.

If you need to open up connectivity between servers in the Cloud VPC, here are some example rules, Inbound and Outbound:

# allow inbound access from 10.0.0.10 to port 2182
# change the IP and port as required
iptables -A INPUT -p tcp --dport 2182 -m state --state NEW,ESTABLISHED -s 10.0.0.10 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 2182 -m state --state ESTABLISHED -j ACCEPT

# allow outbound access to 10.0.0.10 port 514 (eg for rsyslog)
# change the IP and port as required
iptables -A OUTPUT -p tcp --dport 514 -d 10.0.0.10 -j ACCEPT
iptables -A INPUT -p tcp --sport 514 -s 10.0.0.10 -j ACCEPT

# for something like rsyslog, which runs as root, we can be more restrictive
# allow outbound access ONLY TO root to 10.0.0.10:514 (eg for rsyslog)
# not the addition of '-m owner --uid-owner root'
# change the IP and port as required
iptables -A OUTPUT -p tcp --dport 514 -m owner --uid-owner root -d 10.0.0.10 -j ACCEPT
iptables -A INPUT -p tcp --sport 514 -s 10.0.0.10 -j ACCEPT

Here are some handy iptables commands (all need to be run as root, so do a ‘sudo su’ or prefix with ‘sudo’):

# stop iptables
service iptables stop

# start iptables
service iptables start

# cool stuff
watch 'iptables -nvL'

Note that a major problem with iptables is that domain names are resolved when the rule is added and not for every packet. This is probably a good thing because it would mean a lot of DNS lookups… However, if in the rules above you use a domain name (eg an instance DNS name rather than an IP) be aware that if the underlying IP changes, iptables will fail. This applies particularly to RDS services – you can’t fix the IP of an RDS Instance and Amazon recommend connecting via the DNS name, but iptables will resolve the DNS to an IP and if it changes connectivity will be lost. Bear this in mind if you loose database connectivity – to fix, rerun the iptables script.

Frankly, unless you really know what you are doing, I don’t recommend using iptables. The DNS problem mentioned above means your site could experience massive failure if any DNS/IP pairs change. It’s also very unforgiving and I have on several occasions had to terminate and rebuild servers because of a misconfiguration – so MAKE SURE you back everything up before you start playing around with iptables! But, for a simple server which doesn’t communicate much outbound, or only does so to fixed IP addresses, iptables can add very strong extra security.

3 thoughts on “How to Configure iptables on an AWS Instance

  1. aws online training in hyderabad

    Thanks for sharing this- good stuff! Keep up the great work, we look forward to reading more from you in the future!

    Reply
  2. Tony Dawson

    Slight problem with that configuration as it doesn’t take care of the DNS stuff causing the following errors:

    DHCPREQUEST on eth0 to 172.31.0.1 port 67 (xid=0x76082c80)
    dhclient[2250]: send_packet: Operation not permitted
    dhclient[2250]: dhclient.c:2650: Failed to send 300 byte long packet over fallback interface.
    ntpd[2686]: error resolving pool 2.amazon.pool.ntp.org: Temporary failure in name resolution

    What do I need to add?

    Rgds,

    T

    Reply
    1. xianator Post author

      Copy the DNS rules but change the port and IP to 67 and 172.31.0.1
      Be very careful with IPtables unless you know what you are doing…

      Reply

Leave a Reply

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