Hardening iptables from “ACCEPT all” to “DROP all”

Now I write some rules, for hardening iptables. From default policy “accept” everything to “drop” everything except something I want to accept. This setup was made on Server Ubuntu 18.04.2 LTS.

This post is related to and made from sites:

https://help.ubuntu.com/community/IptablesHowTo

https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-using-iptables-on-ubuntu-14-0

By default, we can see, that everything is allowed:

iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination

So we start with allowing established sessions to receive traffic:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

-A INPUT: The -A flag appends a rule to the end of a chain. This is the portion of the command that tells iptables that we wish to add a new rule, that we want that rule added to the end of the chain, and that the chain we want to operate on is the INPUT chain.

And now, we can allow specific port or service, which we want to allow:

iptables -A INPUT -p tcp --dport ssh -j ACCEPT
iptables -A INPUT -p tcp --dport http -j ACCEPT
iptables -A INPUT -p tcp --dport https -j ACCEPT

And now, we block everything else commint to us:

iptables -A INPUT -j DROP

Now we can see our input chain in firewall:

iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:http
ACCEPT tcp -- anywhere anywhere tcp dpt:https
DROP all -- anywhere anywhere

Now we must add some rule for loopback. because we block it now. If we add it right now with above command, we add it at the end of chain (after drop all). So all traffic will be blocked. We must add it at the begining of this chain:

iptables -I INPUT 1 -i lo -j ACCEPT

-I INPUT 1: The -I flag tells iptables to insert a rule. This is different than the -A flag which appends a rule to the end. The -I flag takes a chain and the rule position where you want to insert the new rule.

-i lo: This component of the rule matches if the interface that the packet is using is the “lo” interface. The “lo” interface is another name for the loopback device. This means that any packet using that interface to communicate (packets generated on our server, for our server) should be accepted.

And now we can see it:

iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:http
ACCEPT tcp -- anywhere anywhere tcp dpt:https
DROP all -- anywhere anywhere

The first and the last lines looks very similar, so use the variable -v (verbose) os -S (list rules). See

iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- lo any anywhere anywhere
287 46814 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:http
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:https
211 45230 DROP all -- any any anywhere anywhere
iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -j DROP

Now we have five rules to ACCEPT packets, which we want. The we have the sixth rule for DROP all another packets.

The policy DROP everything can be done by two ways. We have the first way (Default policy of chain is ACCEPT everything. Our five rules catch certain packets and at the end we have the sixth rule to DROP all packet which catch all other remain packets). In case of breaking firewall, or accidentally flush our rules, we still can connect to our server (by default chain policy ACCEPT).

The second way is set default chain policy to DROP, and set our five rules first. So if packets are catch by one of this rules, is ACCEPTed. Then it is DROPPEd by default. There is a possibility, that if we flush our firewall rules, we never reach our server from network because the default chain policy is DROP. So first, we need the rules like above mentioned except the DROP rule. And then, at the end, change the default chain policy by command:

iptables -P INPUT DROP

And now look at this way of firewall:

iptables -S
-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

So we can see, that we DROP all packet, we want and ACCEPT packets we want. It can be done by this two ways. So pick one, which you want. I prefer the second way, because I have another access to server (via console-keyboard connected directly to server). So if something go wrong, I am still be able to connect it.

So if you choose the first way, you must add others rules before the DROP rule, because it will be matched by this rule. Like the loopback rule, you must insert it somewhere before the DROP rules. See the lines:

iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
3 ACCEPT tcp -- anywhere anywhere tcp dpt:http
4 ACCEPT tcp -- anywhere anywhere tcp dpt:https
5 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
6 DROP all -- anywhere anywhere

And now we can add another rule somewhere in the middle:

iptables -I INPUT 6 -p tcp --dport 5666 -j ACCEPT

And we see it:

iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
3 ACCEPT tcp -- anywhere anywhere tcp dpt:http
4 ACCEPT tcp -- anywhere anywhere tcp dpt:https
5 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
6 ACCEPT tcp -- anywhere anywhere tcp dpt:nrpe
7 DROP all -- anywhere anywhere

For save this rules and set it persistant after reboot, I use package:

apt-get install iptables-persistent

During installation you will be asked for some questions, like save this rules for permanent use and load next boot. If you haven’t yet, never mind. You can do it later with this:

iptables-save -c > /etc/iptables/rules.v4

How to set up nfs server on centos 7

Sometimes I need to use fast, simple and no-password storage over the network in bash, or an ISO storage for Xenserver. So nfs sharing is the best way for this.  I have a linux machine with centos 7 and available storage of 1,5TB disk. So, prepare the disk:

fdisk -l /dev/xvdb
> n (new partition), and use default options. The use -t (change partition ID) and change it to 83 (Linux). The use -w (write)
reboot
mkfs.xfs /dev/xvdb1
mkdir /mnt/nfs
mount /dev/xvdb1 /mnt/nfs/

If everything is OK, edit /etc/fstab to automount this partition to ours folder, and add this line:

/dev/xvdb1 /mnt/nfs xfs defaults,nosuid,noatime,nodiratime 0 0

The install package nfs-utils, for nfs server:

yum -y install nfs-utils

And allow nfs service in firewalld:

firewall-cmd --permanent --zone=public --add-service=nfs
firewall-cmd --reload
#if sometimes on clients don't working showmount, and it create an error:
showmount -e 11.22.33.44
rpc mount export: RPC: Unable to receive; errno = No route to host
#we must add another ports to firewall:
firewall-cmd --add-port=2049/tcp --zone=public --permanent
firewall-cmd --add-port=2049/udp --zone=public --permanent
firewall-cmd --add-port=111/udp --zone=public --permanent
firewall-cmd --add-port=111/tcp --zone=public --permanent
firewall-cmd --add-port=662/tcp --zone=public --permanent
firewall-cmd --add-port=662/udp --zone=public --permanent
firewall-cmd --add-port=892/udp --zone=public --permanent
firewall-cmd --add-port=892/tcp --zone=public --permanent
firewall-cmd --reload

And uncoment this lines in: /etc/sysconfig/nfs

MOUNTD_PORT=892
STATD_PORT=662

Now enable nfs-server to run after poweron server and start it:

systemctl enable nfs-server.service
systemctl start nfs-server.service

Now we must prepare this folder with this permissions, for read and write for everybody:

chown nfsnobody:nfsnobody /mnt/nfs/ -R
chmod 755 /mnt/nfs/

And edit file /etc/exports for this folder to by allowed for everybody in network:

/mnt/nfs *(rw,sync,no_root_squash,no_all_squash)

And apply this change:

exportfs -a

We can see our settings with command “exportfs”:

/mnt/nfs        <world>

And from other linux machine, we can mount this folder:

mount 11.22.33.44:/mnt/nfs /mnt/nfs/
#see this disk report space
df -h
Filesystem            Size  Used Avail Use% Mounted on
11.22.33.44:/mnt/nfs
                      1.5T  200G  1.3T  14% /mnt/nfs

And we can test it with 1GB file:

dd if=/dev/zero of=/mnt/nfs/1gb bs=1M count=1000
1048576000 bytes (1.0 GB) copied, 16.4533 s, 63.7 MB/s
...
...
ls -lah /mnt/nfs/
drwxr-xr-x. 18 nfsnobody nfsnobody  4.0K Feb 28 10:47 .
drwxr-xr-x.  3 root      root       4.0K Feb 28 10:24 ..
-rw-r--r--.  1 root      root      1000M Feb 28 10:47 1gb

Have a fun 🙂