Nethence Newdoc Olddoc Lab Your IP BBDock  

Setting up Netfilter (iptables)

as root

Write down what services you want to keep available,

netstat -antupe --inet --inet6 | grep LISTEN

for example, say tcp/22, tcp/389, tcp/636 and a range from tcp/8000 to 8999. And ICMP.

Disable distributor’s firewall and define where your rule set will live depending on your distro. On Debian systems,

#Ubuntu
systemctl stop ufw
systemctl disable ufw

ruleset=/etc/iptables.rules
ruleset6=/etc/iptables.rules6

On Redhat systems,

systemctl stop firewalld
systemctl disable firewalld
yum install iptables-service

ruleset=/etc/sysconfig/iptables
ruleset6=/etc/sysconfig/ip6tables

Check what chains you got e.g. if there is DOCKER,

iptables -L | grep ^Chain

==> see the Docker situation chapter below

Then prepare the rule set restoration file,

cp -pi $ruleset $ruleset.`date +%s`
vi $ruleset

*filter

# policy
:INPUT DROP
:FORWARD DROP
:OUTPUT DROP

# allow ICMP
-A INPUT -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT

# allow all loopback traffic and return all traffic to 127/8 that do not use lo
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
-A OUTPUT ! -o lo -d 127.0.0.0/8 -j REJECT

# accept udp & tcp established inbound connections
-A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT

# allow udp & tcp outbound traffic
-A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT

# allow some inbound tcp ports
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW --dport 389 -j ACCEPT
-A INPUT -p tcp -m state --state NEW --dport 636 -j ACCEPT
-A INPUT -p tcp -m state --state NEW --match multiport --dports 8000:8999 -j ACCEPT

# accept udp & tcp established inbound connections
#-A INPUT -p udp -m state --state RELATED,ESTABLISHED -j ACCEPT
#-A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT

# forcing the existing policy, using REJECT
-A INPUT -j REJECT
-A FORWARD -j REJECT
-A OUTPUT -j REJECT

COMMIT

Note. Dealing with all network interfaces at once here, otherwise add -i netif to the rules.

Ready to go

Now apply and enable the shit,

iptables-restore < $ruleset
#service iptables restore
iptables -L -v

And check that you can ping and reach your services from a remote host and that the rest is truly filtered accordingly (return, not drop) using ping, nmap, netcat, telnet and network clients.

The Docker situation

Ok, you have got Docker in da place. There are two course of action I read about:

  1. let Docker maintain its own rules in the DOCKER chain (opening the mapped ports to the world)
  2. prevent it from managing its rules and take over the shit

The problem with the first solution, which would be acceptable since Docker only opens the needed ports indeed, is that your script or the iptables restore command will conflict with the Docker daemon: you would have to restart it after you apply your own firewall rules, with the unpleasant effect of stopping all the containers. Proceeding with solution 2,

vi /etc/default/docker

DOCKER_OPTS=--iptables=false

ps aux | grep dockerd
service restart docker
ps aux | grep dockerd

so you can now play with your own rules but you need to take care of the Docker needs yourself e.g.,

ifconfig
vi $ruleset

-A FORWARD -i docker0 -o INTERFACE -j ACCEPT
-A FORWARD -i INTERFACE -o docker0 -j ACCEPT

-A FORWARD -p tcp -m state --state NEW --dport 80 -j ACCEPT
-A FORWARD -p tcp -m state --state NEW --dport 443 -j ACCEPT
#-A FORWARD -p tcp -m state --state NEW --dport 4567 -j ACCEPT
#-A FORWARD -p tcp -m state --state NEW --dport 8080 -j ACCEPT

preferably open only the ports you’ve reverse-proxied.

Enable at boot time

On Debian systems,

vi /etc/network/if-pre-up.d/iptables

#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules

chmod +x /etc/network/if-pre-up.d/iptables

On Redhat systems,

cd /etc/sysconfig/
cp -pi iptables-config iptables-config.`date +%s`
cp -pi system-config-securitylevel system-config-securitylevel.`date +%s`
#system-config-securitylevel-tui
chkconfig iptables on
chkconfig ip6tables on

Old school

You can also run a script to then generate the ruleset with iptables-save,

iptables -F
iptables -F -t nat
iptables -F -t mangle
iptables -X
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
...

Fail-safe

To be safe while accessing a remote server and testing new rules, flush those every 5 minutes,

crontab -e

like,

SHELL=/bin/ksh
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
MAILTO=root
HOME=/root
#
*/5 * * * * iptables -F

NAT

To enable NAT,

echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -P FORWARD ACCEPT
iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o eth0 -j MASQUERADE
iptables -A INPUT -i dummy0 -s 10.1.1.0/24 -j ACCEPT
iptables -A OUTPUT -o dummy0 -d 10.1.1.0/24 -j ACCEPT

and to redirect port 80 to 10.1.1.1,

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.1.1.1:80

Note. to enable port redirect, e.g. redirect TCP port 80 to 8080 on eth1,

iptables -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 8080

Misc

Wipe out the rules

Just in case, to totally disable firewalling rules,

iptables -F
iptables -F -t nat
iptables -F -t mangle
iptables -X
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT

check,

iptables -L -v

Trash

# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

If you really want to restrict ICMP to ping (bad idea),

#-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT

you can also add other restrictions to ICMP e.g.,

-A INPUT -p icmp -m state --state NEW,ESTABLISHED -m limit --limit 10/s -j ACCEPT

If you’re experiencing some issues accessing some services, maybe -m state --state NEW is in cause and try without it.

You can define some restrictions for tcp ports e.g.,

#-A INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,RST,ACK SYN -m state --state NEW -m limit --limit 1/s -j ACCEPT
#-A INPUT -p tcp -m tcp --dport 80 --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j ACCEPT

Note. the short and simplest form would be,

#iptables -A INPUT -m state --state NEW -j ACCEPT
#iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Note. also worth interesting,

#... -j REJECT --reject-with tcp-reset

References


Home | GitHub | Donate | Contact