Monday, August 18, 2014

Zen Load Balancer 3.0.3 Perfomance and Security Customization Part 3

Time to do a little network tweaking.

Increase our iptables connection tracking numbers:

ipt_recent parameters:

Note that by default these values are used by ipt_recent module:
ip_list_tot=100     Number of addresses remembered per table
ip_pkt_list_tot=20     Number of packets per address remembered
ip_list_hash_size=0     Hash table size. 0 means to calculate it based on ip_list_tot, default: 512
ip_list_perms=0644     Permissions for /proc/net/ipt_recent/* files
 
root@zen-lb:~# vi /etc/modprobe.d/ipt_recent.conf
options ipt_recent ip_list_tot=3000 ip_pkt_list_tot=100
options xt_recent ip_list_tot=3000 ip_pkt_list_tot=100
options ip_conntrack hashsize=25000
options nf_conntrack hashsize=25000

In some kernels, ipt_recent is xt_recent and ip_conntrack is nf_conntrack, so I've included them all. It won't hurt, but you may get a warning when your system is running about it.

root@zen-lb:~# iptables -F
root@zen-lb:~# modprobe -r ipt_recent
root@zen-lb:~# modprobe ipt_recent  
root@zen-lb:~# modprobe -r xt_recent
root@zen-lb:~# modprobe xt_recent
root@zen-lb:~# modprobe xt_recent
root@zen-lb:~# cat /sys/module/xt_recent/parameters/ip_list_tot
3000
root@zen-lb:~# cat /sys/module/xt_recent/parameters/ip_pkt_list_tot
100

Cool. It worked. Let's get to our iptables rules. Don't forget that your load balancer is a router, so we're going to start off with NAT. We assume that eth0 is our external interface.

root@zen-lb:~# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Now, we create two new iptables tables. One to log and drop illegal packets and another for rate limiting purposes. The latter is especially useful if we have a webserver running.

root@zen-lb:~# iptables -N LOGDROP
root@zen-lb:~# iptables -N RATELIMIT

Our "always accept from the loopback interface" and "always accept related and established connections" rules follow:

root@zen-lb:~# iptables -A INPUT -i lo -j ACCEPT
root@zen-lb:~# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

OK, time to separate the wheat from the chaff. Disallow any type of invalid packets by sending them to our new table, LOGDROP:

root@zen-lb:~# iptables -A INPUT -m state --state INVALID -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp ! --syn -m state --state NEW -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags ALL ALL -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags ALL NONE -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags ACK,PSH PSH -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags ACK,URG URG -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j LOGDROP
root@zen-lb:~# iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOGDROP

Following this, we should add any hosts we trust, such as incoming connections from your VPN and generally any incoming connections that you don't want to add to your rate limit:

root@zen-lb:~# iptables -A INPUT -s 172.16.200.0/24 -j ACCEPT

Now, assuming that we have a webserver running, I am going to allow access to ports 80 (http) and 443 (https). This is not complete access as you can see, as any new connection goes to my RATELIMIT.

root@zen-lb:~# iptables -A INPUT -p tcp -m multiport --dports 80,443 -m state --state NEW -j RATELIMIT

Next, we can add some new trusted connections but this time, not completely trusted. Say some partners. We want them to be actually rate limited, just in case.

root@zen-lb:~# iptables -A INPUT -s 192.168.200.0/24 -j ACCEPT

Now, we'll add ports 80 and 443 once again. Why? Well, if our client hasn't hit our rate limit, they're going to return from our RATELIMIT chain, so we want to accept that.

root@zen:~# iptables -A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
root@zen-lb:~# iptables -A INPUT -m tcp -p tcp --dport 443 -j ACCEPT

And the obligatory "if it doesn't fit any of our aforementioned rules, kill it with fire":

root@zen-lb:~# iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited

Now, once again, our load balancer is a router so we need to enable IP forwarding on it. BUT, for security purposes what we'll do is that we'll only allow it to forward packets from our network to specific hosts, such as NTP, DNS, apt-get and yum update servers. In this example, we assume that the subnets behind our load balancer are the 172.16.104.0/22 and the 172.16.108/24 ones.

root@zen-lb:~# iptables -A FORWARD -s 172.16.104.0/22,172.16.108.0/24 -d 8.8.8.8,8.8.4.4 -j ACCEPT #DNS
root@zen-lb:~# iptables -A FORWARD -s 172.16.104.0/22,172.16.108.0/24 -d 62.1.38.19,62.1.38.25,140.211.169.197,152.19.134.146,66.35.62.166,66.135.62.201,209.132.181.16,67.203.2.67,85.236.55.6,213.175.193.206,195.154.241.117,74.121.199.234 -j ACCEPT #Oracle Linux, EPEL, Remi and Percona Update Servers
root@zen-lb:~# iptables -A FORWARD -s 172.16.104.0/22,172.16.108.0/24 -d 193.93.167.241,79.107.99.220,83.212.114.205,193.239.214.226,83.212.118.71,193.164.227.145,194.177.210.54,83.212.96.50 -j ACCEPT #Red Hat NTP Servers
root@zen-lb:~# iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
root@zen-lb:~# iptables -A FORWARD -j REJECT --reject-with icmp-host-prohibited

Anything that originates from our network should be allowed:

root@zen-lb:~# iptables -A OUTPUT -j ACCEPT

Our LOGDROP chain:

root@zen-lb:~# iptables -A LOGDROP -j LOG --log-prefix "INVALID PACKET:"
root@zen-lb:~# iptables -A LOGDROP -j DROP

And finally our RATELIMIT chain:

root@zen-lb:~# iptables -A RATELIMIT -m recent --set --name RATELIMIT --rsource
root@zen-lb:~# iptables -A RATELIMIT -m recent --rcheck --seconds 5 --hitcount 80 --name RATELIMIT --rsource -j LOG --log-prefix "EXCEEDED RATE:"
root@zen-lb:~# iptables -A RATELIMIT -m recent --rcheck --seconds 5 --hitcount 80 --name RATELIMIT --rsource -j DROP

As you can see, this is extremely liberal. It needs 80 new connections attempts every 5 seconds from the same IP address to start dropping packets. You need to tweak the values according to the needs of your webserver.

Let's make the changes permanent:

root@zen-lb:~# iptables-save > /etc/iptables.up.rules
root@zen-lb:~# vi /etc/init.d/iptables_fw
#!/bin/sh
### BEGIN INIT INFO
# Provides:          iptables_init
# Required-Start:    $local_fs $network
# Required-Stop:
# Default-Start:     2 3 4 5 
# Default-Stop:      0 1 6
# Short-Description: Firewall script
# Description:       Start iptables-based firewall
### END INIT INFO
#
iptables-restore < /etc/iptables.up.rules
 
root@zen-lb:~# iptables-restore < /etc/iptables.up.rules
root@zen-lb:~# chmod 755 /etc/init.d/iptables_fw
root@zen-lb:~# iptables -F
root@zen-lb:~# service iptables_fw start
root@zen-lb:~# update-rc.d iptables_fw defaults

And finally, tell to the kernel that it should allow forwarding as well:

root@zen-lb:~# echo "1" > /proc/sys/net/ipv4/ip_forward
root@zen-lb:~# vi /etc/sysctl.conf
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1


No comments:

Post a Comment